【実務・中級編】 マージ結合 – PostgreSQL

「なぜそのクエリは遅いのか?」— マージ結合(Merge Join)を使いこなすための現場の知恵

やあ。最近、PostgreSQLの実行計画(`EXPLAIN ANALYZE`)と睨めっこしているかい?

実務でパフォーマンスチューニングをしていると、必ずと言っていいほど「Nested Loop」と「Hash Join」の壁にぶつかるよね。でも、大規模データを扱う際、実は一番の頼りになるのは「Merge Join」かもしれない。

今日は、教科書的な説明はさらっと流して、「なぜマージ結合が現場で重宝されるのか」、そして「どうすればPostgreSQLにそれを選ばせられるのか」という、ちょっと踏み込んだ話をしようと思う。

—

そもそもマージ結合って何が凄いの?

簡単に言うと、マージ結合は「ソート済みの2つのリストを、端から順に突き合わせていく」手法だ。

イメージしてみてほしい。バラバラに散らばったトランプのカードを1枚ずつ探すのがNested Loopだとしたら、マージ結合は「あらかじめ数字順に並べ替えた2つのデッキを、左から順番にめくって同じ数字を見つける」作業に近い。

  • Nested Loop: 相手を探すために何度もループするから、データ量が増えると指数関数的に遅くなる。
  • Hash Join: メモリ上に巨大なハッシュテーブルを作るから、メモリが足りないとディスクに溢れて(Spill to disk)地獄を見る。
  • Merge Join: ソートさえ終わっていれば、あとは一筆書き。メモリ消費も比較的穏やかで、データ量が多くても安定感がある。

実践:PostgreSQLはどう動いているのか

PostgreSQLでマージ結合が発動する条件はシンプルだ。「結合キーがソートされていること」。

もしテーブルにインデックスが貼ってあれば、PostgreSQLはわざわざ並べ替え(Sort)を行わずに、インデックスを使って物理的に順序が整ったデータを読み出してくれる。これが決まると、クエリは爆速になる。

例えば、こんな状況を想像してほしい。

— 注文履歴テーブルと顧客マスタの結合
SELECT o.order_id, c.customer_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_date >= ‘2023-01-01’;

もし `orders` テーブルの `customer_id` にインデックスが貼られていて、かつ `customers` テーブルの `customer_id` が主キー(つまりインデックスあり)なら、PostgreSQLは迷わずマージ結合を選択する可能性が高い。

現場でマージ結合を「選ばせる」コツ

ただ、悲しいことにPostgreSQLのオプティマイザは、たまに機嫌を損ねて「Hash Join」を優先してしまうことがあるんだ。特に、データ量がある程度大きい時、「インデックスを使ってソートするコスト」より「ハッシュテーブルを作るコスト」の方が安いと判断されちゃうんだね。

もし、どうしてもマージ結合で安定させたいなら、こんな工夫を試してみてほしい。

1. 結合キーへのインデックス付与を徹底する
基本中の基本だけど、これだけで「Sort」のステップが実行計画から消える。`Index Scan` からの `Merge Join` は最強の布陣だよ。
2. 実行計画を制御する(最後の手段)
どうしてもHash Joinでメモリが溢れるなら、セッション単位で一時的に制御する手もある。

— 一時的にハッシュ結合を無効化してみる(テスト環境でね!)
SET enable_hashjoin = off;
EXPLAIN ANALYZE SELECT …

ただし、これは劇薬だ。本当にマージ結合が最適なのか、それとも単に統計情報が古くてオプティマイザが勘違いしているだけなのか(`ANALYZE`コマンドを忘れてないか確認してくれよな!)、まずはそこを疑うのがプロのやり方だ。

最後に:エンジニアとしての心得

マージ結合は、魔法じゃない。データがソートされていなければ、裏で重たいソート処理が発生して、むしろHash Joinより遅くなることだってある。「とりあえずマージ結合にしておけば安心」なんてことはないんだ。

大切なのは、「なぜPostgreSQLがその実行計画を選んだのか」を想像すること。

`EXPLAIN ANALYZE` を見たときに、「ここでソートが発生しているからコストが高いのか」「いや、インデックスが効いてるからマージが最速だ」と、頭の中でシミュレーションできるようになれば、君も一人前のデータベースエンジニアだ。

もし今、パフォーマンスで悩んでいるクエリがあるなら、一度その結合キーのインデックスを見直してみてくれ。案外、それだけで世界が変わるかもしれないぞ。

それじゃ、今日はこの辺で。また現場で会おう!

コメント

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