我在MySql(5.1)InnoDB中有一个查询,它在一个包含部分的表中搜索。带有零件的表包含大约500 000行。搜索还加入了另外两个表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;
EXPLAIN提供以下内容:(抱歉,我无法弄清楚如何正确格式化)
id select_type table type possible_keys key key_len ref rows extra
1 SIMPLE tblpart ALL NULL NULL NULL NULL 522905 Using where; Using temporary; Using filesort
1 SIMPLE tblcategory eq_ref PRIMARY PRIMARY 4 tblpart.categoryid 1
1 SIMPLE tblheadcategory eq_ref PRIMARY PRIMARY 4 tblcategory.headcategoryid 1
根据我尝试FULLTEXT解决方案的建议:
新的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;
触发器:
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;
答案 0 :(得分:2)
您无法使用前导通配符真正优化查询(即使使用FULLTEXT
次搜索)。
这里唯一可以做的就是将查询拆分为三个(在客户端):
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 = 'bmw'
ORDER BY
tblcategory.category LIKE '%bmw%' DESC
LIMIT 50
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 <> 'bmw'
AND (tblpart.title LIKE '%bmw%' OR tblpart.description LIKE '%bmw%' OR tblpart.brand LIKE '%bmw%')
AND tblcategory.category LIKE '%bmw%'
LIMIT N
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 <> 'bmw'
AND (tblpart.title LIKE '%bmw%' OR tblpart.description LIKE '%bmw%' OR tblpart.brand LIKE '%bmw%')
AND tblcategory.category NOT LIKE '%bmw%'
LIMIT N
并使用N
替换上次查询中的50 - records
,其中records
是先前查询返回的记录数
第一个查询可以使用title
上的索引提供。
<强>更新强>
FULLTEXT
搜索可以像这样实现:
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 ;
新查询:
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_min_word_len
设置为3
或更少,以便它可以为3
- 'BMW'
和'CAR'
等字符字词编制索引。
答案 1 :(得分:0)
索引where子句中使用的字段。我不确定是否有“tblpart.title ='bmw'DESC,tblcategory.category LIKE'%bmw%'DESC”,因为我只做过“索引你的where子句中使用的字段。我不确定tblpart.title DESC,tblcategory.category DESC“
答案 2 :(得分:0)
tblpart.title='bmw' DESC
应该是
已更改为tblpart.title LIKE
'%bmw%' DESC
tblpart.title
和partid
相关的常用搜索字词。现在,只要用户点击搜索,您就会首先搜索此表格,以及搜索字词是否与partid
的查询匹配得更快。