統計情報と実行計画の関係を理解する
MySQL のパフォーマンスチューニングの中で見落とされがちなのが、 MySQL ANALYZE TABLE の役割です。
パフォーマンスが出ないクエリに対してインデックスやSQLの書き方だけに注目しがちです。実は、統計情報の鮮度が見落とされることも少なくありません。MySQLのオプティマイザは、テーブルの中身を直接見るのではなく、統計的な情報を使って実行プランを決定しています。そのため、古くなった統計情報に基づいて選ばれたプランは、現実と大きくズレた非効率なものになりがちです。
ANALYZE TABLE コマンドは、テーブルの統計情報(インデックスのカーディナリティやデータ分布)を更新し、クエリオプティマイザがより正確な実行計画を立てられるようにするためのものです。
この記事では、「推定と実測のズレ」がクエリパフォーマンスに与える影響や、有効な使いどきを具体的な事例とともに紹介していきます。
MySQLバージョンは8.4.5を利用しています。
ANALYZE TABLE とは?
ANALYZE TABLE
は、テーブルやインデックスに関する統計情報を収集し直すコマンドです。
ANALYZE TABLE テーブル名;
この統計情報は、クエリ実行時に使われる EXPLAIN
や EXPLAIN ANALYZE
の rows=
や cost=
の推定に反映されます。
- 統計が古いと → 推定値がズレてしまう
- 推定がズレると → 最適でない実行計画が選ばれてしまう
どんなときに実行すべき?
大量のデータ更新があったとき
- INSERTで10万件以上追加
- DELETEでテーブルの大部分を削除
- UPDATEでインデックス対象カラムの値を大幅に変更
こういった場合は、統計情報が実態を反映していない可能性が高くなります。
推定と実測にズレがあるとき(EXPLAIN ANALYZE)
以下のようなケースでは、ANALYZE TABLEの実行が有効です:
-> Index lookup on orders using idx_user_id (user_id=50000)
(cost=0.35 rows=1)
(actual time=0.012..0.012 rows=0 loops=1)
このように推定rows=1に対し実測rows=0の場合、オプティマイザは誤った判断を下す可能性が高くなります。
CREATE TABLEやストアドプロシージャ作成時は不要
テーブルを作ったばかりの段階では統計情報が意味を持たないため、ANALYZEは不要です。ストアドプロシージャも同様で、クエリの中身が統計に依存するものでなければ関係ありません。
効果を検証:統計更新前後での比較
次のようにテストデータを大量に追加してから ANALYZE TABLE
を実行し、その前後で EXPLAIN ANALYZE
を比較してみます。
-- 統計更新
ANALYZE TABLE orders;
-- クエリの実行計画を確認
EXPLAIN ANALYZE
SELECT *
FROM orders
WHERE user_id = 50000;
この比較により、rows=(推定値)が実測に近づくケースが多く、JOIN順序の選択やインデックスの使用可否に良い影響を与えることが分かります。
ANALYZE TABLE の効果と使いどきまとめ
タイミング | ANALYZE TABLE の必要性 | 理由 |
---|---|---|
テーブル作成直後 | 不要 | まだデータがなく、統計も意味をなさない |
大量のINSERT/DELETE後 | 実行すべき | 統計情報が現状と乖離している可能性が高い |
EXPLAINで推定と実測にズレがある | 実行すべき | 誤った実行計画が選ばれるのを防ぐ |
ストアドプロシージャ作成時 | 不要 | ストプロ自体に統計の概念は関係しない |
パフォーマンスが思ったより出ていないと感じたとき、ANALYZE TABLE
を使って統計情報を最新に保つことで、オプティマイザの判断精度が大幅に改善されることがあります。
これは派手なテクニックではありません。しかし、パフォーマンスチューニングにおける地味で強力な一手です。
今後の検証でもデータを投入後のテーブルに実行していこうと思います。
次回のテーマ
実行計画のキャッシュとSQL再利用の仕組みを見てみようと思います。