「JOINが遅い…」そんな時こそ見てほしい。PostgreSQLの『join_collapse_limit』の話
現場でバリバリコードを書いていると、一度は経験するはずです。「このクエリ、なんでこんなに遅いの?」って。
Explain Analyzeを叩いてみると、JOINの順序がめちゃくちゃだったり、Nested Loopが爆発してたり。そんな時、闇雲にインデックスを貼る前に一度チェックしてほしいのが、PostgreSQLのプランナがどうやって「結合順序」を決めているか、という話です。
今日は、クエリチューニングの隠れた要所、『join_collapse_limit』について解説します。
—
そもそも、PostgreSQLは何をしているのか?
PostgreSQLのクエリプランナは優秀です。あなたが書いた `FROM a JOIN b JOIN c …` というクエリを、そのまま実行するとは限りません。「こっちの順序で結合した方が速いんじゃない?」と、数学的に最適な組み合わせ(コストが最小になる順序)を計算して書き換えてくれるんです。
これを「クエリの再構成」と呼びます。しかし、テーブルの数が増えれば増えるほど、組み合わせの数は指数関数的に増えていきます。10個、20個のテーブルを結合すると、すべての順序を計算するだけでCPUが燃え尽きてしまいますよね。
そこで登場するのが `join_collapse_limit` です。
join_collapse_limit の役割:プランナの「熟考」を制限する
このパラメータは、一言で言えば「プランナが結合順序を入れ替えて検討するテーブル数の上限」です。
- デフォルト値: 8
例えば、あなたが10個のテーブルをJOINするクエリを書いたとします。`join_collapse_limit = 8` の場合、プランナは「最初の8個までは頑張って順序を入れ替えて計算するけど、残りの2個はクエリに書かれた通りの順序で結合するね」という動きをします。
つまり、値を大きくすればするほどプランナは「最適解」を探そうと時間を使い、値を小さくすれば「今の記述通りに速く実行する」ことを優先します。
—
どんな時に調整が必要なの?
実務でこの値をいじるケースは、主に「巨大なJOINが含まれるクエリ」です。
ケース1:プランナが「考えすぎ」で遅い
たまに、JOINが多すぎてプランナが最適解を探すために数秒も止まってしまうことがあります。「いや、そんなのいいから早く動いてくれ!」という時は、この値を小さく(例えば 4〜6 程度に)下げて、探索範囲を制限してあげると、プランナの計算時間が劇的に短縮されます。
ケース2:どうしても特定の順序で実行させたい
「このテーブルとこのテーブルを先に結合して絞り込みたいのに、プランナが変な順序を選択して全表走査(Seq Scan)してる!」なんて経験はありませんか?
本来はクエリの書き方(JOINの順序)で制御すべきですが、どうにもならない時は `join_collapse_limit = 1` に設定してみましょう。こうすると、「書いた通りの順序で結合する」という強制モードになります。
— 一時的に制限を厳しくして実行する例
SET join_collapse_limit = 1;
SELECT
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN … — ここで意図した順序が守られる
—
注意点:魔法の杖ではない
勘違いしてほしくないのは、この設定は「あくまで最後の手段」だということです。
- 設定の副作用: `join_collapse_limit` を小さくしすぎると、本当に効率的な結合経路を見逃してしまい、かえってクエリが遅くなるリスクがあります。
- 根本治療を優先: まずはインデックスの不足や、統計情報が古い(`ANALYZE`してない)ことを疑ってください。PostgreSQLのプランナが変な順序を選ぶのは、往々にして「テーブルの行数が実際と違う」と思い込んでいるからです。
まとめ
- `join_collapse_limit` は、プランナの「脳みそ」をどれだけ使うかを決めるパラメータ。
- 巨大なJOINでプランニング時間自体が長いなら、値を下げるのが有効。
- どうしてもプランナが非効率な順序を選ぶなら、値を1にして「俺の書いた通りにやれ」と指示する。
チューニングは、データとプランナとの「対話」です。Explainの結果を見て、プランナがなぜその選択をしたのかを想像できるようになると、DBエンジニアとしてのレベルが一段上がりますよ。
もし「どうしても最適化できないクエリ」に当たったら、まずはこの設定値をいじって、プランの変化を眺めてみてください。きっと新しい発見があるはずです。
それでは、良いクエリライフを!
コメント