【実務・中級編】 結合手法の制御 – PostgreSQL

PostgreSQLの「プランナの勘違い」を正す――結合制御フラグとの上手な付き合い方

現場でデータベースを触っていると、たまに「なんでオプティマイザはこんな変な実行計画を選んだんだ?」と頭を抱える夜がありますよね。

特に、数千万行のテーブル同士を結合(JOIN)する際、本来ならハッシュ結合でサクッと終わらせてほしいのに、なぜかネステッドループを延々と回してクエリが帰ってこない……なんて経験、一度はあるはずです。

PostgreSQLのプランナは非常に優秀ですが、統計情報の鮮度が落ちていたり、複雑な相関関係があったりすると、たまに「選択肢を読み違える」ことがあります。そんな時、僕たちが介入するための強力なツールが、結合手法を強制的に制御する「フラグ」たちです。

今日は、実務でこの「最後の手段」をどう扱うか、その勘所を解説します。

—

結合制御の「三種の神器」

PostgreSQLには、特定の結合アルゴリズムを無効化するための設定パラメータが用意されています。

  • `enable_nestloop`: ネステッドループ結合を制御。
  • `enable_mergejoin`: マージ結合を制御。
  • `enable_hashjoin`: ハッシュ結合を制御。

これらを `SET enable_hashjoin = off;` のように設定すると、プランナはその手法を「選択肢から外して」計画を作成します。

実務での使いどころ:いきなり「オフ」にするのはNG

まず大切な心構えから。これらのフラグを本番環境のグローバル設定(`postgresql.conf`)でいじるのは絶対に厳禁です。

これをやると、プランナが「本来なら最適なはずの選択肢」さえ選べなくなり、システム全体のパフォーマンスが雪崩のように崩壊する可能性があります。

僕がこれらを使うのは、あくまで「調査」と「一時的な回避」のときだけです。手順としてはこうです。

1. EXPLAIN ANALYZEで現実を確認する:何が起きているか、実際のコストと実行時間を見る。
2. 一時的にOFFにして比較する:トランザクション内だけで特定のフラグをオフにし、実行計画がどう変わるか、時間は短縮されるかを確認する。

— トランザクション内で実行計画の変化を確認する
BEGIN;
SET LOCAL enable_nestloop = off; — 一時的にネステッドループを禁止
EXPLAIN ANALYZE SELECT FROM users u JOIN orders o ON u.id = o.user_id;
ROLLBACK;

こうすれば、他のセッションに影響を与えずに、プランナの挙動をコントロールできます。

なぜプランナは「間違える」のか?

ここが一番面白いところなんですが、実はプランナが間違えているのではなく、僕たちが提供している「統計情報」が間違っていることがほとんどです。

例えば、`WHERE`句で絞り込んだ結果、実は数件しか残らないとわかっているのに、統計情報上は「数万件ある」と判断されていれば、プランナは「全件走査(シーケンシャルスキャン)」を避けようとしてネステッドループを選択し、結果として非効率になることがあります。

もし、特定のフラグをオフにしてパフォーマンスが劇的に改善したなら、それは「プランナが間違ったのではなく、統計情報が実態と乖離している」というサインです。

現場の先輩からのアドバイス

「フラグをいじって速くなった!」で満足してはいけません。それはあくまで応急処置です。その後にやるべきことは一つ。

「なぜプランナはそれを選んだのか? 統計情報を正すにはどうすればいいか?」を考えることです。

  • `ANALYZE` を実行して統計情報を更新する。
  • 相関関係があるカラムなら、`CREATE STATISTICS` で拡張統計情報を作成する。
  • それでもダメなら、クエリの書き方を少し変えて、プランナが理解しやすいヒントを与える。

フラグをいじるのは、あくまで「何が最適か」を見極めるための実験道具として使ってください。この感覚さえ持っていれば、どんなに巨大なデータベースを相手にしても、落ち着いてボトルネックを追い込めるようになります。

—

データベースのチューニングは、プランナという優秀な「助手」との対話です。彼が迷っているときは、少しだけヒント(制御フラグ)を出して、正しい道へ導いてあげましょう。

それでは、また現場で会いましょう。クエリの実行計画が、常に理想的であることを祈っています!

コメント

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