【実務・中級編】 ネステッドループ結合の最適化 – PostgreSQL

「またクエリが遅いってアラートが飛んできてるよ。どれどれ……あー、またネステッドループ(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` を検討しよう。

データベースのチューニングに魔法はないけれど、論理的な裏付けはある。現場で困ったときは、いつでも聞いてくれ。一緒にプランを読み解こうぜ。

コメント

タイトルとURLをコピーしました