その「遅いクエリ」、GEQOの罠かもしれない。PostgreSQLのクエリ最適化の裏側を覗いてみよう
現場でバリバリとSQLを書いていると、たまに「なんでこんなに複雑な結合をしているのに、PostgreSQLは一瞬で実行計画を出せるんだろう?」と不思議に思うことはないかな。
実は、PostgreSQLのクエリプランナは、結合するテーブルが増えれば増えるほど、頭を抱えることになるんだ。今日は、そんなプランナが限界を迎えた時に登場する助っ人、GEQO(Genetic Query Optimizer:遺伝的クエリ最適化)の話をしよう。
結論から言うと、これは「諸刃の剣」だ。使いどころを間違えると、システム全体のパフォーマンスをドブに捨てることになりかねない。現場のエンジニアとして、これだけは知っておいてほしいことをまとめたよ。
—
なぜプランナは「限界」を迎えるのか
通常、PostgreSQLは「動的計画法」を使って、最もコストの低い結合順序を徹底的に探索する。でも、結合するテーブルの数が10個、12個…と増えていくと、探索すべき組み合わせの数は爆発的に増大するんだ。いわゆる「組み合わせ爆発」ってやつだね。
全部の組み合わせを計算していたら、クエリを実行するよりも、計画を立てる時間の方が長くなってしまう。そこで登場するのがGEQOだ。
GEQOの正体:あえて「完璧」を捨て、「そこそこ」を狙う
GEQOは、進化計算の一種である「遺伝的アルゴリズム」を使って、クエリの実行計画を探索する。
簡単に言えば、「全部の組み合わせを調べるのは諦めて、ランダムな組み合わせからスタートして、優秀なものだけを掛け合わせて、まあまあ良い結果を早く見つけようぜ」というアプローチだね。
- メリット: 結合テーブル数が非常に多いクエリでも、プランナがフリーズすることなく実行計画を作成できる。
- デメリット: 遺伝的アルゴリズムなので「最適(ベスト)」な計画ではない可能性がある。つまり、「もっと速い実行計画があるのに、GEQOが選んだせいで遅い計画で実行される」というリスクがあるんだ。
GEQOが発動する「閾値」をコントロールしよう
PostgreSQLでは、`geqo_threshold` というパラメータで「何テーブル以上からGEQOをオンにするか」を制御できる。デフォルトは確か `12` だったはずだ。
— 現在の設定を確認
SHOW geqo_threshold;
もし、君が扱っているシステムで「8テーブルくらいの結合で急にクエリが遅くなる」なんて現象があるなら、デフォルトの12を待たずにGEQOが…いや、逆に、GEQOが動いていないのにプランナが迷走している、あるいはGEQOをオンにした方がマシだったというケースもある。
現場での設定変更は慎重にやるべきだけど、こんなふうにセッション単位で試すのが定石だよ。
— 試しに特定のクエリでGEQOをオフにしてみる
SET geqo = off;
EXPLAIN ANALYZE SELECT FROM table1 JOIN table2 … ;
— ここで実行計画の変化を見る
先輩からのアドバイス:GEQOに頼るな、設計を見直せ
はっきり言うよ。GEQOのお世話になっている時点で、データモデルかクエリの設計に無理があると思った方がいい。
10個も12個もテーブルを結合しなければならないクエリは、往々にして「何でも屋」的な巨大ビューになっていたり、正規化と非正規化のバランスが崩れていたりすることが多い。
もし君のプロジェクトでGEQOの恩恵を受けているなら、まずは以下のチェックリストを確認してみてほしい。
- インデックスは適正か?: 結合列にインデックスがないと、プランナは迷走しやすくなる。
- 統計情報は最新か?: `ANALYZE` を怠ると、プランナは間違った見積もりをしてGEQOに頼らざるを得なくなる。
- 中間テーブルを活用できないか?: あまりに複雑な結合なら、一部をマテリアライズドビューにしたり、テーブルを分割して処理できないか検討しよう。
まとめ
GEQOは、PostgreSQLが持つ「究極の防衛策」だ。でも、君が目指すべきは「GEQOに頼らずとも高速に実行できるクエリを書くこと」だ。
もしクエリが遅いと感じたら、まずは `EXPLAIN` を叩いて、プランナがどう考えているのか覗いてみる。そして、GEQOが関与しているのか、それとも単に統計情報が古いのかを見極める。これができるようになれば、君はもう一段階上のデータベースエンジニアになれるはずだ。
現場でハマったら、また相談してくれよな。応援しているよ!
コメント