全文検索の結果、「FULLTEXT初期化」に費やされる時間が長くなります


12

現在、Stack Overflowのコメントのデータダンプに対していくつかのクエリを実行しようとしています。スキーマは次のようになります。

CREATE TABLE `socomments` (
  `Id` int(11) NOT NULL,
  `PostId` int(11) NOT NULL,
  `Score` int(11) DEFAULT NULL,
  `Text` varchar(600) NOT NULL,
  `CreationDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `UserId` int(11) NOT NULL,
  PRIMARY KEY (`Id`),
  KEY `idx_socomments_PostId` (`PostId`),
  KEY `CreationDate` (`CreationDate`),
  FULLTEXT KEY `Text` (`Text`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

このクエリをテーブルに対して実行し、信じられないほど低速で実行しました(2900万行ありますが、フルテキストインデックスがあります)。

SELECT *
FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)

そこで、私はそれをプロファイルしました。その結果は次のとおりです。

|| Status                     || Duration ||
|| starting                   || 0.000058 ||
|| checking permissions       || 0.000006 ||
|| Opening tables             || 0.000014 ||
|| init                       || 0.000019 ||
|| System lock                || 0.000006 ||
|| optimizing                 || 0.000007 ||
|| statistics                 || 0.000013 ||
|| preparing                  || 0.000005 ||
|| FULLTEXT initialization    || 207.1112 ||
|| executing                  || 0.000009 ||
|| Sending data               || 0.000856 ||
|| end                        || 0.000004 ||
|| query end                  || 0.000004 ||
|| closing tables             || 0.000006 ||
|| freeing items              || 0.000059 ||
|| logging slow query         || 0.000037 ||
|| cleaning up                || 0.000046 ||

ご覧のとおり、FULLTEXTの初期化には長い時間がかかります。これは正常ですか?そうでない場合、どのように修正しますか?


アイデア:1つのテキストフィールドに1.000個のコメントをすべて入れる2番目のテーブルを作成します。ここで、最初にこの2番目のテーブルを検索すると、たとえばid_group 2とが表示されid_group 23ます。これにより、メインテーブル内で検索し、クエリのID範囲を2.000から2.999および23.000から23.999に制限します。もちろん、新しいキーワードの組み合わせを作成するためにすべてのコメントを混ぜると、必要に応じて2番目の結果がより多くなりますが、最終的には全体が高速化されるはずです。もちろん、ディスク容量の使用量は2倍になります。新しいコメントはグループテーブルにCONCATする必要があります。
— mgutt

回答:


5

他の人はこれを厄介な状況だと感じました

以来MySQLのドキュメントは、このスレッドの状態に非常に簡潔です

全文初期化

サーバーは、自然言語の全文検索を実行する準備をしています。

唯一の手段は、より少ないデータで準備を行うことです。どうやって ?

提案#1

クエリをもう一度見てください。すべての列を選択しています。クエリをリファクタリングして、からid列のみを収集しますsocomments。次に、取得したIDをsocommentsテーブルに結合します。

SELECT B.* FROM
(SELECT id FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)) A
LEFT JOIN socomments B USING (id);

これによりいEXPLAINプランが作成される可能性がありますが、プロファイリングはより良くなると思います。基本的な考え方は次のとおりです。積極的なFULLTEXT検索を使用している場合は、そのFULLTEXT initialization段階で収集するデータの量を最小限にして、時間を短縮します。

私はこれを何度もお勧めしました

提案#2

MyISAMのオプションではなく、InnoDBベースのFULLTEXTオプションを設定していることを確認してください。心配する必要がある2つのオプションは

少し考えてみてください。テキストフィールドはVARCHAR(600)です。平均が300バイトだとします。あなたはそれらの29,000,000万を持っています。それは8GBの少しになるでしょう。おそらくinnodb_ft_cache_sizeとinnodb_ft_total_cache_sizeを増やすことも役立つかもしれません。

より大きなInnoDB FULLTEXTバッファーに十分なRAMがあることを確認してください。

試してみる !!!


両方の提案を試してみたところ、時間は約10秒から200秒に短縮されました。奇妙な事は...バッファプールはわずか9%の利用率であるということです
— hichris123

AGAINST部分にプラス記号を入れてみてください:SELECT B.* FROM (SELECT id FROM socomments WHERE MATCH (Text) AGAINST ('+"fixed the post"' IN BOOLEAN MODE)) A LEFT JOIN socomments B USING (id);違いが生じるかどうかを確認してください。
— RolandoMySQLDBA

私がプラス記号を提案した理由は?Doc(dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html)のA leading or trailing plus sign indicates that this word must be present in each row that is returned. InnoDB only supports leading plus signs.場合特定のケースでは、正確なフレーズfixed the postが存在する必要があります。
— RolandoMySQLDBA 14

同じ結果。少し速く、遅くなります。おそらく、実行された時間にわずかな違いがあるためです。
— hichris123 14

5

InnoDB FULLTEXTインデックスを使用している場合、削除された行が多数あるテーブルに対してクエリを実行すると、クエリは「FULLTEXT初期化」状態でハングすることがよくあります。InnoDBのFULLTEXT実装では、影響を受けるテーブルに対して後続のOPTIMIZE操作が実行されるまで、削除された行は整理されません。参照:https : //dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html

削除されたレコードのフルテキストインデックスエントリを削除するには、innodb_optimize_fulltext_only = ONを指定してインデックス付きテーブルでOPTIMIZE TABLEを実行し、フルテキストインデックスを再構築する必要があります。

information_schema.innodb_ft_deletedをクエリすることにより、削除されたがパージされていないレコードの数を調べることもできます。

これを解決するには、InnoDB FULLTEXTインデックスを持つテーブルに対してOPTIMIZE TABLEを定期的に実行する必要があります。


私はこれに関するロジックを取得しますが、それを確認しinnodb_optimize_fulltext_only=1て、OPTIMIZEテーブルが実際に「待機中」に削除された行を処理しますか? dba.stackexchange.com/questions/174486/...
— Riedsio


0

MySQLのフルテキストインデックスは大量のデータをサポートするようには設計されていないため、データセットが大きくなるにつれて検索速度が非常に速く低下します。ソリューションの1つは、SolrやSphinxなどの外部フルテキスト検索エンジンを使用することです。これにより、検索機能(関連性の調整とフレーズ検索のサポート、組み込みファセット、スニペットなど)が拡張され、クエリ構文が中程度になり、速度が大幅に向上します-大規模なデータセット。

SolrはJavaプラットフォームに基づいているため、Javaベースのアプリケーションを実行するのが自然な選択になる場合、SphinxはC ++で記述され、MySQLと同じ方法でデーモンとして機能します。検索したいデータを外部エンジンに供給するとすぐに、いくつかのクエリをMySQLから移動することもできます。どのエンジンがあなたの場合に優れているかはわかりませんが、私は主にSphinxを使用しています。使用例は次のとおりです。http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.