web-dev-qa-db-ja.com

全文検索の結果、「FULLTEXT初期化」に長い時間がかかります

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

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の初期化には長い時間がかかります。これは正常ですか?そうでない場合、どうすれば修正できますか?

12
hichris123

他の人はこれを厄介な状況だと思っています

MySQLドキュメントはこのスレッドの状態が非常に簡潔であるため

フルテキストの初期化

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

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

提案#1

もう一度クエリを見てください。すべての列を選択しています。 socommentsからid列のみを収集するようにクエリをリファクタリングします。次に、取得した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バイトだとします。あなたはそれらの2900万人を持っています。それは8GBの少しになります。おそらく innodb_ft_cache_size および innodb_ft_total_cache_size を増やすことも役立つかもしれません。

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

試してみる !!!

5
RolandoMySQLDBA

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

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

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

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

5
Tyler

MySQLには確認済みのバグがあります( 削除されたDOCIDはInnoDB FULLTEXTテーブルのOPTIMIZEの間は維持されません )削除の負荷が高い場合にパフォーマンスを低下させる(テーブルを最初から再構築しない)。

関連

1
Riedsio

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

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

0
vfedorkov