PostgreSQLにおける実行計画の「制御」:ヒント句なき世界でどう立ち回るか
PostgreSQLを長く触っていると、一度は必ずぶち当たる壁があります。「なぜ、オプティマイザはこれほどまでに不器用なパスを選んでしまうのか」という問いです。
Oracleのような商用DBに慣れ親しんだエンジニアにとって、PostgreSQLにヒント句(`/+ … /`)が標準搭載されていないことは、最初、自由を奪われたような感覚に陥るかもしれません。しかし、PostgreSQLのオプティマイザ(Postgres Optimizer)は、コストベース最適化(CBO)の観点で非常に洗練されています。
今回は、この「ヒント句なき世界」で、いかにして実行計画を意図した方向へ手なずけるか、その深淵を覗いてみましょう。
—
1. 「ヒント句」を導入するという選択肢:pg_hint_plan
まず、現実的な解として挙げられるのが `pg_hint_plan` です。これは、PostgreSQLのクエリパーサにフックし、SQL内のコメントを解析して実行計画を強制的に書き換えるという、極めて強力な拡張機能です。
/+
HashJoin(t1 t2)
SeqScan(t1)
/
SELECT FROM t1 JOIN t2 ON t1.id = t2.id;
なぜこれを使うべきか?
それは、アプリケーションコードを変えずに、特定のクエリの「挙動」を物理的に固定できるからです。緊急時のパフォーマンストラブルシューティングにおいて、これほど精神安定剤になるツールはありません。
ただし、注意が必要な点があります。
`pg_hint_plan` は強力すぎるがゆえに、将来のテーブル統計の変化を無視してしまいます。DBのデータ分布が変わったとき、かつて「最適」だった計画が「最大の足かせ」になる可能性がある。この「時限爆弾」を管理できる自信がある場合のみ、導入を推奨します。
—
2. 統計情報の「演出」:オプティマイザを騙す芸術
もし本番環境で拡張機能の追加が許されない場合、我々に残されたのは「オプティマイザの判断材料を調整する」という手法です。いわば、オプティマイザという名の熟練した職人に、誤った情報を与えて正しい(はずの)選択をさせる、高度な心理戦です。
統計情報の微調整
`ALTER TABLE … ALTER COLUMN … SET STATISTICS` を活用します。
デフォルトの統計収集量では捉えきれない「データの偏り(スキュー)」がある場合、特定のカラムの統計密度を上げることで、Nested LoopかHash Joinかを劇的に変化させることが可能です。
統計情報の「捏造」
極端な手法ですが、`pg_statistic` を直接操作するのは最終手段です。
特定の結合条件において、オプティマイザが不適切な見積もり(カーディナリティの過小評価など)をしている場合、`pg_class` の `reltuples` や `relpages` を意図的に操作して、特定のテーブルを「小さく」あるいは「大きく」見せることで、実行計画を強制的に誘導します。
注意: これはブラックボックス化への入り口です。後に引き継ぐメンバーがその設定を見抜くことはほぼ不可能です。必ずドキュメントを残し、なぜそうせざるを得なかったのかをコードの横に記しておきましょう。
—
3. 最もエレガントな解決策:SQLの再構築
結局のところ、実行計画をいじくり回す前に、もう一度クエリの構造を見直すべきです。PostgreSQLのオプティマイザが迷走するとき、多くの場合、原因は「曖昧なクエリ」にあります。
- CTE(Common Table Expressions)の副作用: PostgreSQL 12以前では、CTEは最適化のバリア(Materialize)として機能していましたが、最新版ではインライン化されます。この挙動の変化により、計画が激変することがあります。`MATERIALIZED` や `NOT MATERIALIZED` を明示的に指定して、オプティマイザの自由度をコントロールしてみてください。
- 結合順序の強制: `JOIN` 句を入れ替えるだけでなく、サブクエリを一度 `CREATE TEMPORARY TABLE` に逃がすだけで、オプティマイザの検索空間を劇的に削減できることがあります。
—
結論:技術の「潔さ」を理解する
PostgreSQLがヒント句を標準で実装しないのには、明確な哲学があります。「統計情報が正しければ、オプティマイザは常に最適解を出す」という信念です。
もし実行計画が悪化しているなら、それは多くの場合、ヒント句が足りないのではなく、統計情報が陳腐化しているか、データモデルが最適化の境界を越えてしまっていることの証明です。
ヒント句や統計情報の操作は、あくまで鎮痛剤です。根本治療は、インデックス設計の見直しや、クエリの構造化、そして何より統計情報が正しく反映されるような運用サイクル(`ANALYZE` のタイミングなど)の構築に他なりません。
泥臭いチューニングを楽しめるか、それとも魔法のようなヒント句に頼るか。エンジニアとしての腕の見せ所は、実はその後者ではなく、前者の「なぜそうなったのか」を解き明かすプロセスにあると、私は信じています。
皆さんのクエリが、今日も効率的に走ることを願っています。
コメント