「クエリが遅い…」と思ったらまず疑うべき、PostgreSQLの『隠れた調整弁』の話
やあ、お疲れ様。最近、PostgreSQLのクエリチューニングで苦戦してない?
「インデックスも貼った、`EXPLAIN ANALYZE`も見た。でも、なぜか実行計画がめちゃくちゃで、クエリが返ってくるまでに時間がかかる…」
そんな時、多くのエンジニアがインデックスの貼り方やハードウェアのスペックばかりに目が行きがちだ。もちろんそれも大事だけど、実はPostgreSQLの「オプティマイザのさじ加減」を調整するだけで、劇的に改善することがあるんだ。
今日は、その中でも少しマニアックだけど、大規模なクエリを扱う現場では避けて通れない`from_collapse_limit`という設定について、実務的な視点で話していこうと思う。
—
そもそも、PostgreSQLは「全部を網羅」しているわけじゃない
まず大前提として知っておいてほしいのは、PostgreSQLのクエリオプティマイザは、どんなに複雑なJOINがあっても「常に世界で最も効率的なプラン」を計算し続けているわけじゃない、ということだ。
もし10個のテーブルをJOINするクエリがあったとして、その結合順序をすべて計算しようとすると、組み合わせの数は爆発的に増える。これを毎回厳密にやっていたら、クエリを投げるたびにCPUが唸りを上げて、プランニングだけで数秒かかってしまうよね。
そこでPostgreSQLは、「ある一定の複雑さを超えたら、多少の非効率は目を瞑って計算を切り上げる」という戦略をとるんだ。その「どこまで頑張るか」を決める境界線が、この`from_collapse_limit`だよ。
- `from_collapse_limit`: サブクエリを外側のクエリとマージして、JOINの並び替え候補にする限界数(デフォルトは8)。
つまり、「8個以上のテーブルをJOINすると、PostgreSQLは最適化を諦め始めて、記述された順序を優先したり、一部をサブクエリとして隔離したりする」というわけだ。
—
こんな時に調整を検討せよ!
実務でこの設定をいじりたくなるのは、大体こういうケースだ。
- 10個以上のテーブルをJOINしている大規模な分析クエリがある
- サブクエリを多用しているせいで、オプティマイザが適切なJOIN順序を選べていない
- `EXPLAIN`を見ると、明らかに不要なサブクエリの境界線でプランが分断されている
例えば、次のようなクエリだ。
SELECT
FROM t1
JOIN t2 ON …
JOIN t3 ON …
— (中略:全部で10個くらいJOINしている)
JOIN t10 ON …
WHERE …;
もしデフォルト値の「8」を超えてこれらがJOINされると、PostgreSQLは「おいおい、組み合わせが多すぎてプランニングに時間がかかりすぎるぞ。もうこの順序で実行しちゃえ!」と、最適化を途中で放棄することがある。これが、現場で「なぜか遅い」クエリの正体だったりするんだ。
—
実践:どうやって調整するか?
もしこの設定を疑うなら、まずは特定のセッションだけで試してみるのが鉄則だ。本番環境のグローバル設定をいきなり変えるのは、リスクが高すぎるからね。
— 現在のセッションだけで制限を緩和する
SET from_collapse_limit = 12;
— この状態で実行計画を確認
EXPLAIN ANALYZE SELECT …;
こうすることで、「12個のテーブルまでは頑張って最適化順序を考えてね」という指示が出せる。これで実行時間が短縮されれば、そのクエリにとっては正解だったということだ。
ただし、注意点もある!
`from_collapse_limit`を大きくしすぎると、今度は「プランニング時間」そのものが増大する。複雑なクエリになればなるほど、プランを立てるための計算コストは指数関数的に跳ね上がるんだ。「クエリは速くなったけど、APIのレスポンスが全体的に遅延した」なんて本末転倒な事態にならないよう、慎重にバランスを見る必要がある。
—
先輩からのアドバイス:設定をいじる前の「もう一歩」
正直に言うと、`from_collapse_limit`をいじるのは、最終手段に近い。まずは以下のことを試してみてほしい。
1. クエリの書き方を見直す: サブクエリを使わずに直接JOINで書けないか検討する(PostgreSQLはJOINの方が圧倒的に最適化しやすい)。
2. `join_collapse_limit`も確認する: `from_collapse_limit`と似ているが、こちらは`JOIN`句で書かれたクエリの結合順序をどこまで組み替えるか決めるものだ。セットで確認すると、より深いチューニングができる。
3. 統計情報を疑う: `ANALYZE`を実行して、テーブルの統計情報が最新か確認する。結局のところ、オプティマイザが「どっちのテーブルが小さいか」を間違えていたら、どんな設定をいじっても無駄だからね。
—
最後に
データベースエンジニアの仕事は、カタログスペック通りの数値を信じることじゃなくて、目の前のデータとクエリの「性格」を見抜くことだ。
`from_collapse_limit`のようなパラメータは、まさにPostgreSQLというエンジンの「チューニングポイント」そのもの。最初は怖がらずに、ぜひ検証環境で遊んでみてほしい。自分の手でクエリの実行計画を劇的に変えられた時の快感は、エンジニア冥利に尽きるものだよ。
また何か詰まったら、いつでも聞きに来てくれ。一緒に最高に速いクエリを追求しようぜ!
コメント