请帮助我优化mysql搜索查询

请帮助我优化mysql搜索查询,mysql,optimization,query-optimization,innodb,full-text-search,Mysql,Optimization,Query Optimization,Innodb,Full Text Search,我在MySql(5.1)InnoDB中有一个查询,它在包含部分的表中搜索。包含零件的表格包含大约500000行。该搜索还连接了另外两个表tblcategory和tblheadcategory。我有很多用户使用这个查询,这使得我的服务器几乎崩溃与沉重的负载 我知道一个很好的方法是使用全文搜索,我希望我们能在将来改变这种方式来使用它。但由于这在InnoDB中是不可能的,我现在需要一个“快速”优化来运行它。我应该如何优化这个和设置索引以及其他事情,以使这个查询尽可能好地运行 以下是查询: SELECT

我在MySql(5.1)InnoDB中有一个查询,它在包含部分的表中搜索。包含零件的表格包含大约500000行。该搜索还连接了另外两个表tblcategory和tblheadcategory。我有很多用户使用这个查询,这使得我的服务器几乎崩溃与沉重的负载

我知道一个很好的方法是使用全文搜索,我希望我们能在将来改变这种方式来使用它。但由于这在InnoDB中是不可能的,我现在需要一个“快速”优化来运行它。我应该如何优化这个和设置索引以及其他事情,以使这个查询尽可能好地运行

以下是查询:

SELECT tblpart.partid,tblpart.title,tblcategory.category,tblheadcategory.headcategory

FROM tblpart

INNER JOIN tblcategory ON tblpart.categoryid = tblcategory.categoryid
INNER JOIN tblheadcategory ON tblcategory.headcategoryid = tblheadcategory.headcategoryid

WHERE (tblpart.title LIKE '%bmw%' OR tblpart.description LIKE '%bmw%' OR tblpart.brand LIKE '%bmw%')

ORDER BY

tblpart.title='bmw' DESC,
tblcategory.category LIKE '%bmw%' DESC

LIMIT 50;
各表:

CREATE TABLE `tblpart` (
    `partid` int(10) NOT NULL auto_increment,
    `userid` int(11) default '1',
    `categoryid` int(10) default '1',
    `title` varchar(100) default NULL,
    `brand` varchar(100) default NULL,
    `description` varchar(100) default NULL,
    PRIMARY KEY  (`partid`),
    KEY `userid` (`userid`),
    KEY `title` (`title`)
) ENGINE=InnoDB AUTO_INCREMENT=534007 DEFAULT CHARSET=utf8;

CREATE TABLE `tblcategory` (
    `categoryid` int(10) NOT NULL auto_increment,
    `category` varchar(255) default NULL,
    `headcategoryid` int(10) default NULL,
      PRIMARY KEY  (`categoryid`)
) ENGINE=InnoDB AUTO_INCREMENT=1261 DEFAULT CHARSET=utf8;

CREATE TABLE `tblheadcategory` (
    `headcategoryid` int(10) NOT NULL auto_increment,
    `headcategory` varchar(255) default NULL,
    PRIMARY KEY  (`headcategoryid`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
解释如下:(对不起,我不知道如何正确格式化)


更新 根据建议,我尝试了全文解决方案:

新的MyISAM表:

CREATE TABLE `tblpart_search` (
    `partid` int(11) NOT NULL AUTO_INCREMENT,
    `title` varchar(100) NOT NULL,
    `brand` varchar(100) DEFAULT NULL,
    `description` varchar(100) DEFAULT NULL,
    PRIMARY KEY (`partid`),
    FULLTEXT KEY `all` (`title`,`brand`,`description`)
) ENGINE=MyISAM AUTO_INCREMENT=359596 DEFAULT CHARSET=utf8;
CREATE TABLE `tblpart_search` (
    `partid` int(11) NOT NULL AUTO_INCREMENT,
    `title` varchar(100) NOT NULL,
    `brand` varchar(100) DEFAULT NULL,
    `description` varchar(100) DEFAULT NULL,
    PRIMARY KEY (`partid`),
    FULLTEXT KEY `all` (`title`,`brand`,`description`)
) ENGINE=MyISAM AUTO_INCREMENT=359596 DEFAULT CHARSET=utf8;
触发因素:

DELIMITER ;;
CREATE TRIGGER `tblpart_insert_trigger` AFTER INSERT ON `tblpart` 
FOR EACH ROW INSERT INTO tblpart_search VALUES(NEW.partid,NEW.title,NEW.brand,NEW.description);;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_update_trigger` AFTER UPDATE ON `tblpart` 
FOR EACH ROW UPDATE tblpart_search SET tblpart_search.title=NEW.title,tblpart_search.brand=NEW.brand,tblpart_search.description=NEW.description WHERE tblpart_search.partid=NEW.partid;;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_delete_trigger` AFTER DELETE ON `tblpart` 
FOR EACH ROW DELETE FROM tblpart_search WHERE tblpart_search.partid=OLD.partid;;
DELIMITER ;
DELIMITER ;;
CREATE TRIGGER `tblpart_insert_trigger` AFTER INSERT ON `tblpart` 
FOR EACH ROW INSERT INTO tblpart_search VALUES(NEW.partid,NEW.title,NEW.brand,NEW.description);;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_update_trigger` AFTER UPDATE ON `tblpart` 
FOR EACH ROW UPDATE tblpart_search SET tblpart_search.title=NEW.title,tblpart_search.brand=NEW.brand,tblpart_search.description=NEW.description WHERE tblpart_search.partid=NEW.partid;;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_delete_trigger` AFTER DELETE ON `tblpart` 
FOR EACH ROW DELETE FROM tblpart_search WHERE tblpart_search.partid=OLD.partid;;
DELIMITER ;
新查询:

SELECT tblpart.partid,tblpart.title,tblcategory.category,tblheadcategory.headcategory

FROM tblpart_search
INNER JOIN tblpart ON tblpart_search.partid = tblpart.partid
INNER JOIN tblcategory ON tblpart.categoryid = tblcategory.categoryid
INNER JOIN tblheadcategory ON tblcategory.headcategoryid = tblheadcategory.headcategoryid

WHERE MATCH (tblpart_search.title, tblpart_search.brand, tblpart_search.description) AGAINST ('bmw,car')
LIMIT 50;
SELECT tblpart.partid,tblpart.title,tblcategory.category,tblheadcategory.headcategory

FROM tblpart_search
INNER JOIN tblpart ON tblpart_search.partid = tblpart.partid
INNER JOIN tblcategory ON tblpart.categoryid = tblcategory.categoryid
INNER JOIN tblheadcategory ON tblcategory.headcategoryid = tblheadcategory.headcategoryid

WHERE MATCH (tblpart_search.title, tblpart_search.brand, tblpart_search.description) AGAINST ('+bmw +car' IN BOOLEAN MODE)
LIMIT 50;

为where子句中使用的字段编制索引。我不确定是否要像“%bmw%”这样的“tblpart.title='bmw'DESC,tblcategory.category”,因为我只做过“为where子句中使用的字段编制索引。我不确定tblpart.title DESC,tblcategory.category DESC”

使用前导通配符(即使使用
全文
搜索)也无法真正优化查询

这里唯一可以做的就是将查询分成三部分(在客户端):

触发因素:

DELIMITER ;;
CREATE TRIGGER `tblpart_insert_trigger` AFTER INSERT ON `tblpart` 
FOR EACH ROW INSERT INTO tblpart_search VALUES(NEW.partid,NEW.title,NEW.brand,NEW.description);;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_update_trigger` AFTER UPDATE ON `tblpart` 
FOR EACH ROW UPDATE tblpart_search SET tblpart_search.title=NEW.title,tblpart_search.brand=NEW.brand,tblpart_search.description=NEW.description WHERE tblpart_search.partid=NEW.partid;;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_delete_trigger` AFTER DELETE ON `tblpart` 
FOR EACH ROW DELETE FROM tblpart_search WHERE tblpart_search.partid=OLD.partid;;
DELIMITER ;
DELIMITER ;;
CREATE TRIGGER `tblpart_insert_trigger` AFTER INSERT ON `tblpart` 
FOR EACH ROW INSERT INTO tblpart_search VALUES(NEW.partid,NEW.title,NEW.brand,NEW.description);;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_update_trigger` AFTER UPDATE ON `tblpart` 
FOR EACH ROW UPDATE tblpart_search SET tblpart_search.title=NEW.title,tblpart_search.brand=NEW.brand,tblpart_search.description=NEW.description WHERE tblpart_search.partid=NEW.partid;;
DELIMITER ;

DELIMITER ;;
CREATE TRIGGER `tblpart_delete_trigger` AFTER DELETE ON `tblpart` 
FOR EACH ROW DELETE FROM tblpart_search WHERE tblpart_search.partid=OLD.partid;;
DELIMITER ;
新查询:

SELECT tblpart.partid,tblpart.title,tblcategory.category,tblheadcategory.headcategory

FROM tblpart_search
INNER JOIN tblpart ON tblpart_search.partid = tblpart.partid
INNER JOIN tblcategory ON tblpart.categoryid = tblcategory.categoryid
INNER JOIN tblheadcategory ON tblcategory.headcategoryid = tblheadcategory.headcategoryid

WHERE MATCH (tblpart_search.title, tblpart_search.brand, tblpart_search.description) AGAINST ('bmw,car')
LIMIT 50;
SELECT tblpart.partid,tblpart.title,tblcategory.category,tblheadcategory.headcategory

FROM tblpart_search
INNER JOIN tblpart ON tblpart_search.partid = tblpart.partid
INNER JOIN tblcategory ON tblpart.categoryid = tblcategory.categoryid
INNER JOIN tblheadcategory ON tblcategory.headcategoryid = tblheadcategory.headcategoryid

WHERE MATCH (tblpart_search.title, tblpart_search.brand, tblpart_search.description) AGAINST ('+bmw +car' IN BOOLEAN MODE)
LIMIT 50;
ft\u min\u word\u len
设置为
3
或更小,以便它可以索引
3
字符单词,如
'BMW'
'CAR'

  • 我认为密码
    tblpart.title='bmw'说明应为
    更改为
    tblpart.title-LIKE
    “%bmw%”说明
  • 创建一个新表,该表将用作文本搜索的索引,您可以在其中存储用户输入的搜索词,以及与
    tblpart.title
    partid
    相关的常用搜索词。现在,每当用户点击search时,您首先搜索该表,如果搜索词与查询匹配,则搜索速度会更快

  • 你能对查询做一个
    解释吗
    ,这样我们就可以看到现有的计划了。即使您提供了足够的信息进行猜测,但看到它总是很好的。
    %%
    如果没有全文搜索,搜索速度总是很慢。我通常使用搜索字段的副本设置MyISAM表,并设置
    FULLTEXT
    索引以链接。@Orbling:使用前导通配符,即使使用
    FULLTEXT
    搜索,它们的速度也会很慢。@Orbling:我试图添加解释部分,但无法在Stackoverflow中将其格式化。.为您格式化,使它崩溃的是制表符,如果你将其转换为空格,则制表符就可以了。
    全文搜索在一定程度上匹配单词和短语,而不是担心通配符,因此比使用类似的词汇匹配要快得多。@Orbling:当然,但逻辑略有不同(尽管这可能不是op想要的).A
    FULLTEXT
    查询在搜索
    ford
    时无法匹配
    Hertfordshire
    @Quassnoi:很对,它不是那样的。如果您需要在单词/字符串中进行任意匹配,那么模式匹配是唯一的方法,而且总是很慢。@Martin:
    创建表ft\u tlbpart(id INT NOT NULL主键,title TEXT NOT NULL,FULLTEXT KEY(title))ENGINE=MyISAM;INSERT INTO_tblpart SELECT id,title FROM tblpart;
    。这很难。但请注意,从现在起,您必须对这两个表进行插入、更新和删除(可以通过触发器解决)@Martin:如果你将服务器设置调整为最小字长(默认为4),它将只匹配MySQL中的3个字母的单词,这是人们通常不知道的一个主要问题。谢谢你的回答!索引会有帮助吗?即使我使用通配符?查询的排序部分是否会减慢速度?是的-当然。你想确保where和sort子句已正确索引。还可以查看全文搜索/索引性能。