【テクニカル・上級編】 実行計画制御パラメータ (enable_seqscan等) – PostgreSQL

「enable_」系パラメータという諸刃の剣 — プランナの挙動をねじ伏せる前に知っておくべきこと

PostgreSQLの運用を長く続けていると、一度は必ず誘惑に駆られる瞬間があるはずです。

「なぜ、ここはIndex Scanじゃないんだ?」
「Nested Loopの方が速いと分かっているのに、なぜプランナはHash Joinを選ぶ?」

そんな時、目の前に現れるのが `enable_seqscan` や `enable_indexscan`、あるいは `enable_hashjoin` といった、いわゆる実行計画制御パラメータ群です。これらを `off` にして特定のアルゴリズムを封印し、プランナを無理やり従わせる。現場では「禁断のテクニック」のように扱われることもありますが、これ、実は使い方を間違えるとシステムを奈落の底へ突き落とすことになりかねません。

今日は、この「神の視点」を一時的に手に入れるためのパラメータについて、少し深い話をしてみましょう。

—

なぜプランナは「間違った」選択をするのか

まず前提として、PostgreSQLのプランナは非常に優秀です。しかし、彼らは「万能」ではありません。プランナがアルゴリズムを選択する際、主にテーブルの統計情報(`pg_stats`)とコストモデルに基づいて計算を行いますが、ここにはいくつか落とし穴があります。

1. 統計情報の鮮度の欠如: ANALYZEが走っていない、あるいはデータ分布が極端に偏っている場合。
2. コストパラメータの不一致: `seq_page_cost` や `random_page_cost` がハードウェア構成(SSD vs HDD)と乖離している場合。
3. 相関関係の考慮不足: 複数の列にまたがる複雑なフィルタ条件がある場合、個別の統計情報の積で計算されるため、プランナは行数を過小評価しがちです。

こうした「前提条件の崩れ」が、最適ではない実行計画を生みます。ここで `enable_seqscan = off` を使うと、確かにその場は Index Scan に強制できます。しかし、それは「プランナの判断プロセスを無視している」という事実に他なりません。

パラメータを操作する:検証と「その先」

私がこれらのパラメータを推奨するのは、本番環境の恒久的な回避策としてではなく、「ボトルネックの真因を特定するための検証ツール」としてです。

例えば、特定のクエリが遅いとき、`SET enable_seqscan = off;` を実行して EXPLAIN ANALYZE を取ってみる。もし、強制的にIndex Scanに変えた結果として「劇的に速くなった」のであれば、問題は「プランナがコスト見積もりに失敗している」か「統計情報の質が低い」かのどちらかです。

ここで終わらせてはいけません。本来すべきなのは:

  • 統計情報を更新してみる(`ANALYZE`)
  • 拡張統計情報(`CREATE STATISTICS`)を使って相関関係をプランナに教える
  • 適切なインデックスを検討する
  • そもそもハードウェアコストの設定を見直す(近年のNVMe環境であれば `random_page_cost` は 1.1 程度が妥当なことも多い)

これらを飛ばしてパラメータを `off` にしたまま放置するのは、風邪の症状に対して解熱剤だけを打ち続け、病気の根本治療を放棄するようなものです。

してはいけないこと、そして例外

これらパラメータの運用において、最も避けるべきは 「セッションレベルではなく、グローバル設定(postgresql.conf)で永続的に変更すること」 です。

あるクエリのために `enable_hashjoin = off` を設定したとしましょう。その結果、本来 Hash Join が適しているはずの他の数千ものクエリまでが、より効率の悪い Nested Loop や Merge Join に引きずり込まれる。システム全体のパフォーマンスが雪崩を打って崩壊する、という光景を私は何度か見てきました。

ただ、例外もあります。
移行直後や、統計情報がどうしても追いつかない特殊なバッチ処理など、「このトランザクションの間だけ、特定のプランを強制したい」というケースです。この場合、`SET LOCAL` を用いてトランザクションのスコープ内に限定してください。

BEGIN;
SET LOCAL enable_seqscan = off;
— ここに最適化したい複雑なクエリ
COMMIT;

これなら、副作用を最小限に抑えつつ、狙った挙動だけを引き出せます。

最後に:プランナを「飼い慣らす」ということ

PostgreSQLのエンジンは、私たちが思っている以上に賢く、そして繊細です。`enable_` パラメータをいじることは、エンジニアとして「プランナに対して自分の直感をぶつける」行為でもあります。

しかし、技術の深淵を覗くのであれば、パラメータで挙動をねじ伏せる快感に溺れるのではなく、「なぜプランナはその選択をしたのか?」という理由を読み解く力を養ってほしいのです。

実行計画のツリーを見て、コストの計算式に思いを馳せ、統計情報の偏りを感じ取る。そうしてエンジンの内側を理解した上で、パラメータを「最後の手段」として切り出す。それこそが、データベースエンジニアとしての真の熟練度ではないでしょうか。

さて、今日の設定値、本当にそのままで大丈夫ですか?一度 `EXPLAIN` の奥底を、もう一度見直してみるのもいいかもしれませんね。

コメント

タイトルとURLをコピーしました