Skip to content

MySQL FULLTEXTが遅い理由

データ量や同時アクセスが増えると、MySQL FULLTEXTの検索が実用上のボトルネックになることがあります。その原因と解決策を解説します。

何が問題なのか

同じクエリでも、2つのアーキテクチャではたどるデータパスがまったく異なります。一方はディスク上の構造体を経由し、もう一方はすべてRAM上で完結します。

ディスクI/Oがボトルネック

MySQL FULLTEXTはインデックスをディスク上のB-treeに保存しています。検索のたびに:

  1. ディスクからB-treeページを読み込み
  2. ポスティングリストをメモリに展開
  3. 結果のソート(大抵は外部ソート)

SSDを使っていても、このI/Oオーバーヘッドが大きくなり、ベンチマークではクエリによって数百msから数秒かかりました。

用語補足

ポスティングリストは「この語を含むドキュメントIDの一覧」です。全文検索は、この一覧同士をAND/ORで組み合わせて候補を探します。詳しくは用語集を参照してください。

ポスティングリストが非圧縮

MySQLはポスティングリストを圧縮しません。「の」「を」のような頻出語で数百万件ヒットすると:

  • クエリごとに数MBのデータを読み込む
  • バッファプールを圧迫
  • 並列アクセスでキャッシュが効かなくなる

キャッシュ頼み

キャッシュの状態で性能が大きく変わります。公開ベンチマークでは、キャッシュヒットではなく検索エンジン自体を比べるため、MygramDBのクエリキャッシュを無効にしています。

本番環境では再起動・デプロイ・メモリ競合でキャッシュが効かない状況が頻発します。

並列アクセスで伸びにくい

並列アクセスでは、MySQL FULLTEXTのスループットが伸びにくくなることがあります。1接続・4接続のキャッシュ無効時の結果と測定条件は、ベンチマークに集約しています。

解決策:MygramDB

MygramDBはアーキテクチャから見直すことでこれらの問題を解決しています。

検索インデックスをメモリ上に保持

検索インデックスはRAM上に保持されます。MySQL FULLTEXTのように、検索のたびにディスク上の全文検索インデックスへ戻る構成ではありません。

圧縮されたポスティングリスト

デルタエンコーディングとRoaringビットマップで、ポスティングリストを圧縮して保持します。頻度の低い語と高い語で表現を切り替えることで、メモリ使用量と検索速度のバランスを取ります。

SIMD命令で高速化

ビットマップ演算にCPUのSIMD命令を活用し、スループットを最大化。

キャッシュ状態に左右されにくい性能

インデックスをメモリ上に持つため、検索のたびにMySQLのFULLTEXTインデックスへ戻る必要がありません。キャッシュ無効時の実測値はベンチマークをご覧ください。

MySQL / MariaDBのbinlogに追従

GTIDベースのbinlogレプリケーションで、MySQL 8.4/9.xまたはMariaDB 10.6+/11.xの変更に追従します。検索用のETLパイプラインは不要です。反映遅延は通常小さくなりますが、MySQL側の負荷、ネットワーク、MygramDBの処理状況によって変動します。

用語補足

ETL はデータを抽出(Extract)し、変換(Transform)し、別システムへ投入(Load)する仕組みです。MygramDBはMySQLのbinlogを直接読むため、検索用の同期ジョブを別途作る必要がありません。

向いているケース

  • 高トラフィックなWebサービス — ECサイト、ニュースサイト、Q&Aサービスなど同時アクセスが多い環境
  • リアルタイム検索が必要 — ユーザーが即座に結果を期待する場面
  • FULLTEXTが100ms超 — 検索の遅さがUXを損なっている
  • 負荷時にタイムアウト — アクセス集中で検索が落ちる

試してみるならクイックスタートへ。詳しくはGitHubをご覧ください。