全文検索の結果、「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_sizeinnodb_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.