小さいテーブルからハッシュテーブルを構築し、大きいテーブルで検索する2フェーズの結合アルゴリズム。等価結合に最適でO(N+M)
Hash Join(ハッシュ結合)は、小さい方のテーブルからインメモリのハッシュテーブルを構築(Build)し、大きい方のテーブルの各行でハッシュテーブルを検索(Probe)する2フェーズのJOINアルゴリズムです。計算量は O(N + M) で、ソートを必要とせず、等価結合において最も高速なアルゴリズムの一つです。
電話帳で名前を探す場面を想像してください。まず50音順の索引ページ(ハッシュテーブル)を作ります。次に、探したい名前のリストを上から順番に、索引を使って素早く該当ページを開きます。一つの名前につき索引を1回引くだけなので、名簿を最初から最後まで探す必要がありません。この「O(1)ルックアップ」がHash Joinの効率の源です。
PostgreSQLではHash Joinとして実装されており、等価結合のデフォルトとして最も頻繁に選ばれるアルゴリズムです。EXPLAINで Hash Join と表示されればこのアルゴリズムが使われています。ハッシュテーブルの構築にはwork_memが使われ、メモリに収まらない場合はディスクにスピルします。
-- 等価結合(=)でインデックスなし → Hash Joinが最適 SELECT e.name, d.dept_name FROM employees e JOIN departments d ON e.dept_id = d.id; -- PostgreSQLのEXPLAINで確認 EXPLAIN SELECT e.name, d.dept_name FROM employees e JOIN departments d ON e.dept_id = d.id; -- → "Hash Join" + "Hash" と表示されればHash Joinが使われている
左側のdepartments(部署)テーブルをビルドテーブルとしてハッシュテーブルを構築し、右側のemployees(社員)テーブルをプローブテーブルとして検索します。結合キーは departments.id = employees.dept_id です。
具体的なデータ例: departments.id = [1, 2, 3, 4] の4行からハッシュテーブルを構築します。次に employees.dept_id = [1, 2, 1, 3, 2, 5] の6行で検索し、dept_id=5の渡辺以外の5行がマッチします。
矢印はBuildフェーズではビルドテーブルからハッシュテーブルへのデータ流入を、Probeフェーズではプローブテーブルからハッシュテーブルへの検索を表しています。緑の実線はマッチ(ヒット)、赤の破線はミス(不一致)を示します。
小さい方のテーブル(departments)の各行を結合キー(id)でハッシュし、バケットに格納します。ハッシュ関数により、同じキーは常に同じバケットに入ります。
大きい方のテーブル(employees)の各行でハッシュテーブルを検索します。O(1)でバケットにアクセスし、マッチ/ミスを判定します。
ハッシュテーブルは結合キーをハッシュ関数に通してバケット番号を決定します。同じキーは同じバケットに入り、O(1)でアクセスできます。
SET work_mem = '256MB'; でセッション単位で調整できますが、同時接続数分のメモリが必要です。SELECT * FROM logs JOIN sessions ON logs.session_id = sessions.id のように、一時テーブルやログテーブルの結合で頻繁に使われます。WITH active_users AS (...) SELECT * FROM orders JOIN active_users ON ... のように、CTEやサブクエリの結果セットとの結合。中間結果にはインデックスがないため、Hash Joinが唯一の高速な選択肢になります。EXPLAIN ANALYZEでHash Batchesを確認しましょう。Hashと表示される側がBuildです。| アルゴリズム | 計算量 | メモリ | 得意な場面 | 苦手な場面 |
|---|---|---|---|---|
| Hash Join | O(N+M) | O(N) | 等価結合、インデックス無 | 不等価結合、メモリ不足 |
| Sort-Merge | O(NlogN+M) | O(N+M) | ソート済み、大規模 | ソートコスト大 |
| Nested Loop | O(N×M) | O(1) | 小規模、選択的 | 大規模テーブル |
| Index NLJ | O(N×logM) | O(1) | インデックス有、選択的 | インデックス無し |