「複雑なJOIN」の深淵:PostgreSQLのプランナを制御する `from_collapse_limit` の知られざる挙動
PostgreSQLのクエリプランナと向き合っていると、たまに「なぜそんな回りくどい実行計画を立てるんだ?」と頭を抱えたくなる瞬間がありますよね。特に、数十のテーブルが絡み合う巨大なJOINクエリを投げたとき、プランナがいつまでも計算を終えなかったり、あるいは意図しない結合順序を選択してクエリが爆発的に遅くなったりする。
そんなとき、多くのエンジニアが `enable_seqscan` といった禁じ手に手を出しがちですが、実はもっと根源的な「プランナの思考回路」を制御するパラメータがあることを忘れてはいけません。それが `from_collapse_limit` です。
今回は、このあまり語られない、しかし極めて重要なチューニングパラメータについて、少し深掘りしてみましょう。
—
1. プランナにとっての「迷宮」:JOINの順序問題
まず前提として、PostgreSQLのプランナは、JOINの順序を最適化するために動的計画法(Dynamic Programming)を用いています。参加するテーブルが増えれば増えるほど、検討すべき組み合わせは指数関数的に増えていく。
ここで登場するのが `from_collapse_limit` です。このパラメータは、プランナが「サブクエリやJOINの入れ子構造をどこまでフラットに展開して、ひとつの大きなJOINの塊として再検討するか」の境界線を決めています。
- デフォルトは 8:つまり、8テーブル以下のJOINであれば、プランナはすべての組み合わせを網羅的に探索しようとします。
- 展開の意図:サブクエリをフラットに展開することで、本来は別々のコンテキストだったテーブル同士をJOIN順序の候補に含めることができます。これにより、より効率的なNested LoopやHash Joinの組み合わせが見つかる可能性が高まるわけです。
2. なぜデフォルト値で「詰む」ことがあるのか
一見すると「すべて展開したほうが賢いプランが見つかるのでは?」と思いがちです。しかし、これが曲者なんです。
10個、15個とテーブルが増えていくと、`from_collapse_limit` を超えた瞬間に、プランナは「これ以上、全探索するのはコストが見合わない」と判断します。すると、「元のクエリで指定されたJOIN順序を維持する」という、極めて保守的な挙動に切り替わります。
これが「なぜか特定のクエリだけ極端に遅い」というトラブルの典型的な原因です。本来なら結合順序を入れ替えるだけで劇的に速くなるはずのクエリが、サブクエリの境界に縛り付けられ、効率の悪いJOIN順序を強制されている。この状況に陥ると、インデックスをどれだけ最適化しても効果は限定的です。
3. 現場でのチューニング:いつ手を出すべきか
このパラメータを調整する際は、慎重なアプローチが必要です。闇雲に数値を上げれば、今度はプランニング(解析)時間そのものが数秒に伸びるリスクがあるからです。
もし、あなたの環境で以下のような兆候が見られるなら、`from_collapse_limit` の調整を検討する価値があります。
- Explain Analyzeで見て、明らかに「結合順序がおかしい」場合:特に大きなテーブル同士が先にJOINされていて、中間結果が巨大になっているケース。
- クエリの解析時間が異常に長い場合:逆に、テーブル数が少ないのにプランニングに時間がかかっているなら、数値を下げることで探索範囲を限定し、プランニングコストを抑えることができます。
調整のステップ
1. 影響範囲の特定:まずはセッション単位で設定をいじってみましょう。
`SET from_collapse_limit = 12;`
これだけで解決するクエリがあるなら、それはプランナがこれまで「見えなかった最適解」に辿り着けた証拠です。
2. プランニング時間の監視:`EXPLAIN ANALYZE` の出力にある「Planning Time」を確認してください。ここがミリ秒単位から数百ミリ秒単位に跳ね上がるようであれば、上げすぎです。
3. JOINの強制:もし `from_collapse_limit` をいじりたくない場合は、CTE(`WITH`句)を使って明示的に最適化の境界を作るという古典的かつ確実な手法もあります。PostgreSQL 12以降はCTEのインライン化も改善されていますが、複雑なケースでは依然として有効な防波堤になります。
4. 最後に:DBエンジニアの勘所
結局のところ、`from_collapse_limit` は「プランナの知能の幅」を規定するスイッチです。
「このクエリはこれ以上複雑にするな」という設計上の制約をDBに伝えるのか、それとも「もっと広い視野で考えてくれ」とAIを信じるのか。その判断基準は、クエリの構造をどれだけ深く理解しているかに委ねられています。
DBのチューニングは、単なる数値合わせではありません。オプティマイザがどのような計算コストを払って「最善」を導き出そうとしているのか、そのプロセスを想像する力こそが、熟練のDBエンジニアの武器になるはずです。
皆さんのクエリが、今日より少しだけ速く終わることを願っています。また深淵なトピックがあれば、ここでお会いしましょう。
コメント