実行計画という名の「地図」を読み解く:PostgreSQLにおけるEXPLAINの深淵
PostgreSQLを触り始めてしばらく経つと、誰もが一度は「なぜこのクエリはこんなに遅いんだ?」という壁にぶつかります。その時、真っ先に叩くのが `EXPLAIN` コマンドでしょう。
しかし、多くのエンジニアが `EXPLAIN` の出力結果を「なんとなく」眺めて、`Seq Scan` が出ているからインデックスを貼る、といった表層的な対応で終わらせてしまっています。熟練のエンジニアであれば、その一歩先――オプティマイザがなぜその結論に至ったのか、その「思考のプロセス」を読み解かなければなりません。
今日は、単なるコマンド解説ではない、PostgreSQLの内部構造に踏み込んだ「実行計画との対話術」について語ろうと思います。
—
「コスト」という名の抽象概念を疑え
まず大前提として、`EXPLAIN` が表示する `cost=0.00..431.00` といった数値は、ミリ秒単位の実行時間ではありません。これはPostgreSQLのプランナが内部的に算出している「相対的な負荷の指標」です。
このコスト計算の裏側には、`seq_page_cost` や `random_page_cost` といった設定値が存在します。もし、SSD環境なのにデフォルトの(HDDを想定した) `random_page_cost` のまま運用しているなら、プランナはインデックススキャンを過度に嫌い、シーケンシャルスキャンを優先するような「歪んだ地図」を描き続けます。
`EXPLAIN` を見る際は、まず「自分の環境の統計情報とコスト設定は、現実のハードウェアと乖離していないか?」を自問することから始めてください。
実行計画を「動的に」検証する:EXPLAIN ANALYZEの罠
`EXPLAIN` 単体ではプランナの予測に過ぎません。実際にクエリを流して実測値を得る `EXPLAIN ANALYZE` は強力ですが、ここには大きな落とし穴があります。
- 書き込み系クエリでの注意: `EXPLAIN ANALYZE` は実際にクエリを実行するため、`UPDATE` や `DELETE` につけるとデータが書き換わります。必ず `BEGIN` でトランザクションを貼り、検証後に `ROLLBACK` する癖をつけましょう。
- 統計情報の鮮度: `ANALYZE` 直後の統計情報と、数日間更新されていない統計情報では、実行計画が激変することがあります。特にデータ分布が偏っているカラムに対しては、`CREATE STATISTICS` を駆使して、相関関係をプランナに教えてやる必要があります。
「コストの乖離」こそが、パフォーマンストラブルの源泉
私がトラブルシューティングで最も注視するのは、`EXPLAIN ANALYZE` の結果における 「Estimated rows(予測行数)」と「Actual rows(実測行数)」の乖離 です。
もしここが数桁以上ずれているなら、それはプランナが「データ分布を誤認している」証拠です。この乖離が起きると、プランナは以下のいずれかの「地雷」を踏みます。
1. Nested Loopの選択: 本来ならHash Joinが適しているはずなのに、行数を過小評価してNested Loopを選び、結果として指数関数的に時間がかかる。
2. 不適切なインデックススキャン: 大量データに対してインデックスを引こうとし、ランダムアクセスが爆発する。
この乖離を埋めるためには、単にインデックスを増やすのではなく、`ALTER TABLE … SET STATISTICS` で対象カラムのヒストグラムの精度を上げたり、複合インデックスを検討してフィルタリングの効率を高める必要があります。
最後に:プランナを「信じすぎない」勇気
経験を積んだエンジニアほど、PostgreSQLのオプティマイザを信頼しがちです。しかし、PostgreSQLのプランナは完璧ではありません。時に、我々人間の方が「このテーブルとこのテーブルは、この条件ならこう結合した方が速い」というメタ的な知識を持っていることがあります。
どうしてもプランナが最適解を出さない時、私は `set enable_seqscan = off;` のような安易なヒント句に頼る前に、以下のことを考えます。
- クエリの書き換え: 副問い合わせをJOINに直す、あるいはその逆。
- 物理的なデータ配置: `CLUSTER` コマンドを使ってテーブルの物理順序をインデックスと合わせる。
- 中間テーブルの活用: 複雑すぎるクエリを一時テーブルに分割し、プランナが探索する空間を物理的に小さくする。
`EXPLAIN` は、単なるデバッグツールではありません。それは、データベースエンジンの「思考」を可視化する鏡です。その鏡に映る歪みを一つずつ丁寧に正していくプロセスこそが、データベースチューニングの醍醐味ではないでしょうか。
皆さんのクエリが、明日から少しでも軽やかに走ることを願っています。
コメント