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
は例です。言葉はいくつあってもいい。クエリの最後の数字は単語の総数です。アイデアは、スレッドには検索クエリ内のほとんどすべての単語が含まれており、任意の数の投稿に分散しているということです。
このクエリは、たった 2 語で 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 に重複したインデックスがある理由がわかりません。ただし、これは古くて気まぐれなソフトウェアであるため、削除するつもりはありません。