「またクエリが遅いってアラートが飛んできてるよ。どれどれ……あー、またネステッドループ(Nested Loop)が暴れてるね」
PostgreSQLを触っていると、一度は必ず遭遇するこの「Nested Loop」。初心者向けの本には「最悪の結合方式」なんて書かれがちだけど、それは大きな誤解だよ。使い方さえ間違えなければ、これほど頼もしい武器はないんだ。
今日は、現場の第一線で戦う君のために、PostgreSQLのNested Loopとどう付き合っていくべきか、その本質を紐解いていこう。
—
そもそも、Nested Loopって何がそんなに嫌われてるの?
Nested Loopの仕組みは単純そのもの。外側のテーブル(Outer)の行を1つずつ取り出して、内側のテーブル(Inner)をスキャンしてマッチするものを探す。
もし、どちらのテーブルもフルスキャン(Seq Scan)しかできないとしたら……そう、計算量は「外側の行数 × 内側の行数」になる。データが増えれば増えるほど、地獄のような遅延が待っているわけだ。これが「Nested Loop=悪」というレッテルを貼られた理由だね。
でも、考えてみてほしい。もし「内側のテーブルへの検索」がインデックスで一瞬で終わるとしたら?
—
魔法の条件:「インデックス」と「小さなデータセット」
PostgreSQLのオプティマイザがNested Loopを選ぶとき、裏ではこんな計算が働いているんだ。
1. Outerテーブルのサイズが小さい:ループ回数が少なくて済む。
2. Innerテーブルの結合キーに適切なインデックスがある:インデックスを使って、O(log N)でピンポイントにデータが引ける。
この条件が揃ったとき、Nested LoopはHash JoinやMerge Joinを圧倒する速度を叩き出す。メモリを大量に消費することもないし、結果を待たずに最初の行を返せる(レイテンシが極めて低い)から、Webアプリのレスポンス向上には欠かせないんだよ。
—
実践:どうやって最適化するか?
じゃあ、実際に現場でチューニングするときのアプローチを教えるね。
1. `EXPLAIN ANALYZE` で「見積もり」と「現実」のギャップを見る
まずはこれ。`EXPLAIN ANALYZE` を実行して、プランを見てみよう。
EXPLAIN ANALYZE
SELECT users.name, orders.amount
FROM users
JOIN orders ON users.id = orders.user_id
WHERE users.id = 12345;
ここで注目すべきは、`actual time` と `rows`。
もし `rows` の見積もりが実際と大きく乖離しているなら、統計情報(ANALYZE)が古い可能性がある。PostgreSQLは統計情報に基づいて「Nested Loopが速いか」を判断しているから、ここがズレていると迷走するんだ。
2. インデックスが効いているか確認する
Nested Loopが遅いとき、原因の9割はこれ。インデックスが使われていない、あるいはインデックスが効かない(関数インデックスが必要なケースなど)。
例えば、`orders` テーブルの `user_id` にインデックスを貼るだけで、Nested Loopのコストは劇的に下がる。
— 鉄板の改善策
CREATE INDEX idx_orders_user_id ON orders(user_id);
3. どうしても遅いなら「強制」は最終手段
オプティマイザがどうしてもNested Loopを選んでくれない、あるいは逆に選んでほしくない場合は、設定で制御することもできる。
— セッション単位で一時的に変更してテストする
SET enable_nestloop = off;
ただ、これを本番環境で安易に使うのは禁じ手だよ。あくまで「なぜオプティマイザはそう判断したのか?」を追求するための検証ツールとして使おう。
—
先輩からのアドバイス:怖がる必要はない
Nested Loopは、PostgreSQLが「これ、インデックスで一撃で取れるからループしたほうが速いよ!」と自信満々に提案してくれているサインなんだ。
もし実行計画を見てNested Loopが多用されていたら、「なんでこれを選んだんだ? ああ、このテーブルは件数が少ないし、インデックスが完璧だからか」と、まずはオプティマイザの意図を汲み取ってみてほしい。
逆に、Nested LoopがSeq Scan(フルスキャン)を伴って実行されているなら、それは「インデックスが足りていない」という悲鳴だ。そのときは迷わず `CREATE INDEX` を検討しよう。
データベースのチューニングに魔法はないけれど、論理的な裏付けはある。現場で困ったときは、いつでも聞いてくれ。一緒にプランを読み解こうぜ。
コメント