У меня есть запрос в MySql (5.1) InnoDB, который ищет в таблице с частями. Таблица с частями содержит около 500 000 строк. Поиск также объединяет две другие таблицы tblcategory и tblheadcategory. У меня много пользователей, использующих этот запрос, и из-за большой нагрузки мой сервер практически падает.
Я знаю, что хорошим способом было бы использовать полнотекстовый поиск для этого, и я надеюсь, что мы можем изменить это, чтобы использовать его в будущем. Но так как это невозможно с InnoDB, мне нужна «быстрая» оптимизация, чтобы запустить его сейчас. Как мне оптимизировать это и настроить Index и другие вещи, чтобы этот запрос работал как можно лучше?
Это запрос:
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
UPDATE
Из предложений я попробовал решение 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;