web-dev-qa-db-ja.com

mysqlのフルテキストクエリが遅い

全文索引を使用するmysql-queryのパフォーマンスに少し問題があります。

次のクエリ

SELECT Mention.id
FROM mentions AS Mention  
WHERE (MATCH (`Mention`.`title_text`, `Mention`.`content_text`, `Mention`.`author_text`) 
AGAINST ('"hannover 96"' IN BOOLEAN MODE))

約3秒かかります。

Fulltext-conditionを次のように変更した場合

SELECT Mention.id
FROM mentions AS Mention  
WHERE (MATCH (`Mention`.`title_text`, `Mention`.`content_text`, `Mention`.`author_text`) 
AGAINST ('+hannover +96' IN BOOLEAN MODE))

クエリの所要時間は約0.001秒です。

それで、最初のクエリのパフォーマンスを向上させる可能性はありますか? 「hannover 96」という文字列全体を検索することが重要です。hannoverと96を含むレコードは検索しないでください。

ヒントをありがとう!

宜しくお願いします、

ティモ

2
Timo

クエリのWHERE句が完全に異なるものを要求しています

  • クエリ#1:MATCH句で言及されている3つの列内の正確な文字列hannover 96
  • クエリ#2:hannover句で言及されている3つの列内の2つの文字列MATCHおよび96

フルテキストインデックスはトークンを非常にうまくインデックス化します。したがって、複数のトークンを含む正確な文字列は、処理に時間がかかるはずです。

hannover 96をより速く見つける唯一の方法は、サブクエリを使用することです。

SELECT B.* FROM
(SELECT Mention.id FROM mentions AS Mention  
WHERE (MATCH (`Mention`.`title_text`,`Mention`.`content_text`,`Mention`.`author_text`) 
AGAINST ('+hannover +96' IN BOOLEAN MODE))) A
INNER JOIN Mention B USING (id)
WHERE LOCATE('hannover 96',CONCAT(title_text,content_text,author_text)) > 0;

または

SELECT B.* FROM
(SELECT Mention.id FROM mentions AS Mention  
WHERE (MATCH (`Mention`.`title_text`,`Mention`.`content_text`,`Mention`.`author_text`) 
AGAINST ('+hannover +96' IN BOOLEAN MODE))) A
INNER JOIN Mention B USING (id)
WHERE LOCATE('hannover 96',  title_text) > 0
OR    LOCATE('hannover 96',content_text) > 0
OR    LOCATE('hannover 96', author_text) > 0;

試してみる !!!

2
RolandoMySQLDBA

最初のクエリが遅い理由を説明できますが、2番目のクエリが速い理由は説明できません。 :)

私の理論では、ft_min_Word_lenはシステムで「2」より長い(デフォルトは4)ため、「Word」「96」は実際にはフルテキストインデックスになりません...全表スキャン、または少なくとも、インデックスに「ハノーバー」を含むすべての行を見つけ、最終的な基準に一致しない行を破棄する必要があります。残念ながら、フルテキストインデックスを含むクエリに関しては、EXPLAIN SELECTは通常ほど価値がありません。明らかに、そのインデックスが試行されるかどうかを通知するだけです。

これらを見てください:

https://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html

https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_ft_min_Word_len

そうでない場合は、クエリをベンチマークするときにSELECT SQL_NO_CACHE ...を使用することをお勧めします。または、一見すると高速なクエリキャッシュからの応答を取得している可能性があります。

2