実行プランナという「最強の頭脳」との対話
PostgreSQLを長年触っていると、たまに不思議な感覚に陥ることがある。クエリを投げた瞬間、わずか数ミリ秒で最適解を導き出す「プランナ」という存在に、まるで熟練の職人と向き合っているような敬意を感じるからだ。
しかし、その職人も万能ではない。統計情報が古びていたり、相関関係を見誤ったりすれば、途端に的外れな実行計画を提示してくる。今日は、このPostgreSQLの心臓部であるクエリプランナと、どうすればより良い「対話」ができるかについて、少し深い話をしようと思う。
—
コストモデルの裏側を覗く
PostgreSQLのプランナは「コストベースオプティマイザ(CBO)」だ。ここで言う「コスト」とは、実行時間そのものではなく、ディスクI/OやCPU負荷を抽象化した数値に過ぎない。
多くのエンジニアが陥る罠は、このコストを「絶対的な正解」だと信じ込んでしまうことだ。だが、プランナが計算しているのはあくまで「最善である確率が高いパス」であり、その精度は `pg_stats` に格納されたヒストグラムや相関値に完全に依存している。
もし皆さんが「なぜこんな変なスキャンを選択したんだ?」と頭を抱えたら、まずはプランナが何を前提条件にしているのかを疑うべきだ。
統計情報の「嘘」を見抜く
プランナは、テーブルの行数やデータの分布が統計情報通りだと信じ切っている。しかし、以下のようなケースでは簡単に足元をすくわれる。
- 相関のあるカラム: `WHERE city = ‘Tokyo’ AND zip_code = ‘100-0001’` のような条件。プランナはこれらを独立した確率として計算するため、積集合の行数を過小評価し、ネステッドループを選択して爆死することがある。
- 複雑な式: `WHERE UPPER(name) = ‘YAMADA’` のような書き方をすると、カラム統計は無視され、デフォルトの選択率(0.33%など)が適用される。これが大規模テーブルで発生すると、プランナはインデックスを無視してフルスキャンを選択する確率が跳ね上がる。
—
プランナを「正しく誘導」するための技術
プランナが迷子になったとき、僕らはどう介入すべきか。闇雲にクエリを書き換えるのは、場当たり的な対処療法に過ぎない。
1. 統計情報の解像度を上げる
まずは `ALTER TABLE … ALTER COLUMN … SET STATISTICS` だ。デフォルトの100という値は、あくまで汎用的なもの。データの偏りが激しいカラムや、複合条件で頻繁に検索されるカラムには、迷わず500や1000を割り当ててみてほしい。これだけで、プランナが見せる表情が劇的に変わることがある。
2. 「物理的な構造」をヒントにする
PostgreSQLにはオラクルでいう「ヒント句」が(公式には)存在しない。これは設計思想だ。「プランナを信頼せよ」というメッセージでもある。しかし、どうしてもプランナが最適解を選ばない場合、以下のようなテクニックで「物理的制約」を与えることができる。
- CTE(WITH句)の活用: 古いバージョンでは `MATERIALIZED` 属性を制御することで、プランナの最適化の境界線を作れた。最新のPGでは挙動が変わっているが、実行計画を分断させる手段として依然として有効だ。
- 無害な演算子の付加: インデックスを使わせたいカラムに `+ 0` を足すような姑息な手段は推奨しないが、`WHERE col = val` の代わりに `WHERE col IN (val)` と書くことで、プランナの評価順序が変わることもある。
—
トラブルシューティングの極意:EXPLAIN ANALYZE を読み解く
「なぜ遅いのか?」という問いに対し、`EXPLAIN ANALYZE` の結果を眺めるだけでは不十分だ。重要なのは、「見積もり(Estimated)」と「実績(Actual)」の乖離を見つけることだ。
— 読み方のコツ
-> Index Scan using … (cost=0.42..8.14 rows=1 width=8) (actual time=0.045..0.046 rows=1000 loops=1)
この `rows=1` に対して `actual rows=1000` となっている場所こそが、プランナが地雷を踏んでいるポイントだ。なぜ見積もりがズレたのか? 統計情報の不備か、式による計算不能か。そこまで掘り下げて初めて、真のパフォーマンスチューニングと言える。
—
最後に:ツールではなく「パートナー」として
PostgreSQLのプランナは、年々進化している。特に近年のバージョンでは、インデックスのスキャン効率やパラレルクエリの最適化において、驚くべき進歩を見せている。
エンジニアとしての僕らの仕事は、プランナを出し抜くことではない。プランナが正確な見積もりを行えるよう、インデックスを適切に張り、統計情報を最新に保ち、クエリの意図を明確にする「土壌」を作ることだ。
機械的なコードを書くのではなく、データベースという「生き物」の思考プロセスを理解する。そうすれば、複雑なクエリの実行計画が、まるで美しい数式のように納得できるものに変わるはずだ。
次はぜひ、あなたの環境の `EXPLAIN` 結果を、プランナの視点になって読み解いてみてほしい。きっと、これまで見えなかったボトルネックが、向こうから語りかけてくるはずだ。
コメント