金融システムの夜間バッチでは、大量データのJOINで処理が遅くなることがあります。
本記事では、**JOINの種類と内部アルゴリズム(Nested Loop / Hash Join / Merge Join)**を直感的に整理し、データ量別のパフォーマンスを比較します。
JOINとは?
SQLでいう JOIN は「複数のテーブルを条件で組み合わせて1つの結果を作る操作」
例:
SELECT *
FROM transactions t
JOIN customers c ON t.customer_id = c.customer_id;
JOIN = 目的(結合したい)
実際にどう結合するかはアルゴリズム次第(手段)
JOINの内部アルゴリズム
PostgreSQLの主要アルゴリズムは3種類:
アルゴリズム イメージ 計算量 ポイント
Nested Loop Join
外側テーブル1行ずつ、内側テーブルを探索 O(n×m) 小規模向き、大きいと爆発
Hash Join
小さいテーブルをハッシュ化、もう片方を順番に照合 O(n+m) 小テーブルはメモリに乗る必要あり、メモリ不足でspill
Merge Join
両方をソートして順番にマージ O(n log n + m log m)(ソート込み) ソート済みなら高速&安定、大規模向き
アルゴリズムごとの処理イメージ
Nested Loop Join
外側 = 「順番に1行ずつ見るテーブル」
内側 = 「外側の行に合わせて検索するテーブル」
小さいテーブル×大きいテーブルならOK
大きいテーブル同士だと二重ループで爆発
Hash Join
小さいテーブルを ハッシュ化(メモリ上に展開)
大きいテーブルを1行ずつ照合
メモリ不足時は spill(ディスク退避) が発生し遅くなる
Merge Join
両方を結合キーでソート
順番に比較しながら結合
計算量は O(n log n + m log m)、ソート済みなら O(n+m)
大規模データでも安定して高速
データ量別パフォーマンス比較
データ量-少ない
Nested Loop 高速、シンプル
Hash Join 高速、ほぼO(n+m)
Merge Join ソートコストがあるのでNested Loopより遅い場合も
データ量-多い
Nested Loop 遅い、二重ループで爆発
Hash Join 高速(小テーブルがメモリに乗る場合)
Merge Join 高速&安定、ソート済みならO(n+m)
金融システム夜間バッチの実務ポイント:
小規模データ → Nested Loopで十分
中規模〜大規模 → Hash Join、高速化のためwork_memやハッシュサイズに注意
大規模・ソート済み → Merge Joinで安定
用語整理
用語 意味
JOIN(結合) 複数のテーブルを条件で組み合わせるSQL操作(目的)
Nested Loop / Hash / Merge JOINを実行する内部アルゴリズム(手段)
マージ(merge) Merge Join内部で「順番に照合して結合する」処理
work_mem PostgreSQL がソート・Hash Join・GROUP BYなどの一時作業に使うメモリ量。小さいとディスクに一時書き出し(spill)される
spill work_mem に入りきらないデータを 一時的にディスクに書き出すこと。処理は続くが遅くなる
実務で意識するポイント
①JOIN前に絞り込み → 不要な行を減らす
②インデックス設計 → JOINキーやWHERE句に必須
③EXPLAINで実行計画確認
EXPLAIN (ANALYZE, BUFFERS) SELECT ...
SELECT *
FROM transactions t
JOIN customers c ON t.customer_id = c.customer_id;
得られる情報:
どのテーブル・インデックスが使われたか
内部JOINアルゴリズム(Nested Loop / Hash / Merge)
実行時間
ディスクI/Oの回数(shared hit, read, dirtied, written)
④Hash Joinのspill対策 → work_mem設定
⑤Merge Join活用 → 両方ソート済みデータは大量でも安定
まとめ
Nested Loop = 二重ループ、小規模向き
Hash Join = 小テーブルを辞書化して高速検索
Merge Join = 両方ソート済みなら順番にマージ、高速&安定