現在、スタックオーバーフローのコメントのデータダンプに対していくつかのクエリを実行しようとしています。スキーマは次のようになります。
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の初期化には長い時間がかかります。これは正常ですか?そうでない場合、どうすれば修正できますか?
他の人はこれを厄介な状況だと思っています
MySQLドキュメントはこのスレッドの状態が非常に簡潔であるため
フルテキストの初期化
サーバーは自然言語の全文検索を実行する準備をしています。
あなたの唯一の手段は、より少ないデータで準備をすることです。どうやって ?
もう一度クエリを見てください。すべての列を選択しています。 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
フェーズ。時間を短縮します。
私はこれを何度も勧めました
May 14, 2012
: フルテキストと左結合の遅いクエリMar 18, 2012
: MySQLのFULLTEXTインデックスでMATCH ... AGAINSTよりもLIKEが4倍以上速いのはなぜですか?Jan 26, 2012
: Mysql全文検索my.cnf最適化 :Oct 25, 2011
: 「ワード数」を条件とするブールモードでは、FULLTEXTインデックスは無視されますMyISAMのオプションではなく、InnoDBベースのFULLTEXTオプションを設定していることを確認してください。懸念すべき2つのオプションは
少し考えてみてください。テキストフィールドはVARCHAR(600)です。平均が300バイトだとします。あなたはそれらの2900万人を持っています。それは8GBの少しになります。おそらく innodb_ft_cache_size および innodb_ft_total_cache_size を増やすことも役立つかもしれません。
より大きなInnoDB FULLTEXTバッファーに十分なRAMがあることを確認してください。
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を定期的に実行する必要があります。
MySQLには確認済みのバグがあります( 削除されたDOCIDはInnoDB FULLTEXTテーブルのOPTIMIZEの間は維持されません )削除の負荷が高い場合にパフォーマンスを低下させる(テーブルを最初から再構築しない)。
関連 。
MySQLのフルテキストインデックスは大量のデータをサポートするように設計されていないため、データセットが大きくなるにつれて検索速度は非常に速く低下します。解決策の1つは、SolrやSphinxなどの外部全文検索エンジンを使用することです。これは、検索機能(関連性の調整とフレーズ検索のサポート、組み込みのファセット、スニペットなど)を拡張し、クエリ構文を拡張し、中速での速度を大幅に向上させます。 -大きなデータセット。
SolrはJavaプラットフォームに基づいているため、Javaベースのアプリケーションを実行するのが自然な選択である場合、SphinxはC++で記述され、MySQLと同じようにデーモンとして機能します。すぐに検索したいデータを外部エンジンにフィードするときに、MySQLからいくつかのクエリを移動することもできます。私はあなたのケースでどちらのエンジンが優れているかはわかりません。私は主にSphinxを使用しています。使用例は次のとおりです http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/