【发布时间】:2013-09-03 12:50:09
【问题描述】:
我正在尝试优化快速优化一些用 PHP 编写的过时论坛软件的搜索功能。我将我的工作归结为一个如下所示的查询:
SELECT thread.threadid
FROM thread AS thread
INNER JOIN word AS word ON (word.title LIKE 'word1' OR word.title LIKE 'word2')
INNER JOIN postindex AS postindex ON (postindex.wordid = word.wordid)
INNER JOIN post AS postquery ON (postquery.postid = postindex.postid)
WHERE thread.threadid = postquery.threadid
GROUP BY thread.threadid
HAVING COUNT(DISTINCT word.wordid) = 2
LIMIT 25;
word1 和 word2 是示例;可以有任意数量的单词。查询末尾的数字是单词的总数。这个想法是,一个线程最包含搜索查询中的所有单词,分布在任意数量的帖子中。
这个查询经常超过 60 秒,只有两个词,并且超时。我很难过;我不知道如何进一步优化这个可怕的搜索引擎。
据我所知,所有内容都已正确编入索引,并且我最近运行了ANALYZE。大多数数据库都在 InnoDB 上运行。这是EXPLAIN的输出:
+----+-------------+-----------+--------+----------------------------------------------------------------------------------------+---------+---------+------------------------------+------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+--------+----------------------------------------------------------------------------------------+---------+---------+------------------------------+------+-----------------------------------------------------------+
| 1 | SIMPLE | word | range | PRIMARY,title | title | 150 | NULL | 2 | Using where; Using index; Using temporary; Using filesort |
| 1 | SIMPLE | postindex | ref | wordid,temp_ix | temp_ix | 4 | database1.word.wordid | 3 | Using index condition |
| 1 | SIMPLE | postquery | eq_ref | PRIMARY,threadid,showthread | PRIMARY | 4 | database1.postindex.postid | 1 | NULL |
| 1 | SIMPLE | thread | eq_ref | PRIMARY,forumid,postuserid,pollid,title,lastpost,dateline,prefixid,tweeted,firstpostid | PRIMARY | 4 | database1.postquery.threadid | 1 | Using index |
+----+-------------+-----------+--------+----------------------------------------------------------------------------------------+---------+---------+------------------------------+------+-----------------------------------------------------------+
更新
LIMIT 25 似乎没有多大帮助。它可能会比通常返回数百个结果的查询减少第二次。
澄清
使 MySQL 变慢的部分是 GROUP BY ... HAVING ... 位。对于GROUP BY,LIMIT 对于提高性能几乎毫无用处。没有GROUP BY,只要LIMIT还在,查询速度还是蛮快的。
SQL 信息
SHOW CREATE TABLE postindex; 的输出:
CREATE TABLE `postindex` (
`wordid` int(10) unsigned NOT NULL DEFAULT '0',
`postid` int(10) unsigned NOT NULL DEFAULT '0',
`intitle` smallint(5) unsigned NOT NULL DEFAULT '0',
`score` smallint(5) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY `wordid` (`wordid`,`postid`),
KEY `temp_ix` (`wordid`),
KEY `postid` (`postid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
我没有制作表格,所以我不知道为什么 wordid 上有重复的索引;但是,我不愿意删除它,因为这是一个古老的、变化无常的软件。
【问题讨论】:
-
这看起来很脏,很脏:“INNER JOIN word AS word ON (word.title LIKE 'word1' OR word.title LIKE 'word2')”
-
@PieterB 关于
word AS word:第一个word不保证是word;它可能有一个前缀。此查询由 PHP 生成。 -
word.title上有索引。我相信它被整理为 utf8_swedish_ci(它是从使用 latin1_swedish_ci 的数据库中导入的)。在 PHP 中规范化字符串并使用相等而不是
LIKE可能会有所帮助。 -
问题在于“LIKE”,再多的索引也不会变得更快,据我所知,如果我错了,有人纠正我 INNODB 也不支持全文搜索.
-
@PieterB 我们使用的是 5.6; InnoDB 从 5.6 开始支持全文搜索。
标签: php mysql sql query-optimization mysql-5.6