MySQL FULLTEXTが遅い理由
データ量が増えるとMySQL FULLTEXTは使い物にならないほど遅くなります。その原因と解決策を解説します。
何が問題なのか
ディスクI/Oがボトルネック
MySQL FULLTEXTはインデックスをディスク上のB-treeに保存しています。検索のたびに:
- ディスクからB-treeページを読み込み
- ポスティングリストをメモリに展開
- 結果のソート(大抵は外部ソート)
SSDを使っていても、このI/Oオーバーヘッドだけで100〜3000msかかります。
ポスティングリストが非圧縮
MySQLはポスティングリストを圧縮しません。「の」「を」のような頻出語で数百万件ヒットすると:
- クエリごとに数MBのデータを読み込む
- バッファプールを圧迫
- 並列アクセスでキャッシュが効かなくなる
キャッシュ頼み
キャッシュの状態で性能が2〜3倍変わります:
| 状態 | クエリ時間 |
|---|---|
| キャッシュなし | 2,980ms |
| キャッシュあり | 908ms |
本番環境では再起動・デプロイ・メモリ競合でキャッシュが効かない状況が頻発します。
並列アクセスで破綻
負荷がかかるとMySQL FULLTEXTは壊滅します:
| 並列数 | 成功率 | 平均応答 |
|---|---|---|
| 1 | 100% | 908ms |
| 10 | 10% | 4,641ms |
| 100 | 0% | タイムアウト |
たった10並列で9割のクエリが失敗します。
解決策:MygramDB
MygramDBはアーキテクチャから見直すことでこれらの問題を解決しています。
すべてメモリ上
インデックスは全部RAM上。クエリ中のディスクアクセスはゼロです。
圧縮されたポスティングリスト
デルタエンコーディングとRoaringビットマップで、メモリ使用量を60〜80%削減。しかも検索は速くなります。
SIMD命令で高速化
ビットマップ演算にCPUのSIMD命令を活用し、スループットを最大化。
常に安定した性能
キャッシュの暖機運転は不要。いつでも80ms以下で応答します。
| 並列数 | 成功率 | 平均応答 |
|---|---|---|
| 1 | 100% | 32ms |
| 10 | 100% | 35ms |
| 100 | 100% | 190ms |
MySQLとリアルタイム同期
GTIDベースのbinlogレプリケーションでMySQLと自動同期。ETLパイプラインは不要、データの遅延もありません。
こんなサービスに最適
- 高トラフィックなWebサービス — ECサイト、ニュースサイト、Q&Aサービスなど同時アクセスが多い環境
- リアルタイム検索が必要 — ユーザーが即座に結果を期待する場面
- FULLTEXTが100ms超 — 検索の遅さがUXを損なっている
- 負荷時にタイムアウト — アクセス集中で検索が落ちる
始め方
bash
docker run -d --name mygramdb \
-p 11016:11016 \
-e MYSQL_HOST=your-mysql-host \
-e MYSQL_USER=repl_user \
-e MYSQL_PASSWORD=your_password \
-e MYSQL_DATABASE=mydb \
-e TABLE_NAME=articles \
ghcr.io/libraz/mygram-db:latest詳しくはGitHubをご覧ください。