TL

分散結合戦略(broadcast・shuffle・sort-merge)

分散JOINが遅いのは、たいてい結合戦略の選択を誤っているからです。小表を配るブロードキャスト、両表を再分配するシャッフル、大表どうしのソートマージを、いつ何が選ばれるかの判断基準ごと原理から押さえられます。

応用分散結合シャッフルブロードキャスト結合ソートマージデータスキュー分析基盤最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.分散結合の骨格は三つ。ブロードキャストハッシュ結合は小さい方の表を全ノードへ複製し、大表をローカルでハッシュ照合するのでシャッフルが片側で済む。両表が大きいときはシャッフル結合で結合キーのハッシュにより両表を再分配し、同じキーを同じノードへ集めてから結合する。
  • 2.ソートマージ結合はシャッフル後に両表を結合キーでソートし、2本のソート済みストリームを同時走査(マージ)して照合する。ハッシュ表がメモリに載らない大規模結合やスピルに強く、多くのエンジンで大表どうしの既定になる。
  • 3.戦略選択はコストベースで決まる。片方が閾値(例 Sparkの既定10MB)以下ならブロードキャスト、そうでなければシャッフル系。両表が同じキーで同じ数のバケット/分散に事前配置されていればシャッフル自体を省ける。最大の落とし穴は結合キーの偏りで、ホットキーが1ノードを潰す。

なぜ分散環境では「結合戦略」が問題になるのか

1台のDBなら、結合の主な選択肢はネステッドループ・ハッシュ結合・ソートマージ結合で、勝負はインデックスとメモリの範囲に収まります。ところがデータが数百ノードに分割された分析基盤では、話が一段変わります。同じ結合キーを持つ行が、別々のノードに散らばっているからです。ノードN1にある注文行の相手(顧客行)が、ノードN7に載っているかもしれない。この状態で結合を成立させるには、まず照合すべき行どうしを同じノードへ集める必要があり、そのデータ移動こそが分散結合のコストの本体です。

つまり分散結合の設計は、結合アルゴリズムそのものより、**「どちらの表を、どうやってノード間で動かすか」**の選択です。この移動戦略が主に三つ——ブロードキャストシャッフルソートマージ——であり、どれを選ぶかで実行時間が桁で変わります。移動を伴う再分配は、/data-engineering/mapreduce-shuffle/ で見た all-to-all のシャッフルと同じ性質を持ち、分散処理で最も高コストな操作です。

分散結合の三段構え

分散結合はふつう「再分配フェーズ(データを正しいノードへ動かす)」と「ローカル結合フェーズ(各ノード内で照合する)」の二段で捉えます。ローカル結合には単一ノードと同じハッシュ結合やソートマージが使われますが、その前段の再分配の設計が戦略の違いを生みます。ブロードキャストは片方だけを全ノードへ複製、シャッフルは両方をキーで再分配、そして再分配後にソートで照合するのがソートマージです。

ブロードキャストハッシュ結合:小さい方を配って片側のシャッフルを消す

一方の表が十分に小さい(マスタ表・ディメンション表など)なら、最も速いのはブロードキャストハッシュ結合(broadcast hash join)です。手順はこうです。まず小さい表を全ノードへまるごと複製して配り、各ノードのメモリ上にその表のハッシュ表を作る。次に大きい表は動かさず、各ノードが自分の持ち分の行を1件ずつハッシュ表に問い合わせて照合する。

小表S(数MB)を全ノードへ複製、各ノードでハッシュ表を構築
大表L はそのまま(再分配なし)
  ノードN1: L の担当行 → メモリ上の S ハッシュ表を lookup → 出力
  ノードN2: L の担当行 → 同じ S ハッシュ表を lookup → 出力
  …
→ 大表 L のネットワーク移動はゼロ

肝は大表を一切シャッフルしない点です。全対全の再分配が消え、代わりに小表を配る片方向のブロードキャスト(合計で「小表サイズ×ノード数」程度)だけで済みます。大表が巨大でも小表が数MBなら、これが圧倒的に有利になります。制約は明確で、複製した小表のハッシュ表が各ノードのメモリに載りきる必要があること。だからエンジンは「小さい方のサイズが閾値以下か」を選択の第一基準にします(Sparkの spark.sql.autoBroadcastJoinThreshold は既定10MB)。

サイズ見積もりを外すとブロードキャストは牙をむく

ブロードキャストの可否はオプティマイザのサイズ推定に依存します。統計が古い・フィルタ後の行数を読み違える・圧縮列の展開後サイズを過小評価する、といった理由で「小さいはず」の表が実は大きいと、全ノードのメモリを圧迫してOOMやGC地獄を招きます。逆に本当は小さいのに統計欠如で閾値超えと誤判定すると、無用なシャッフル結合に落ちて遅くなります。実務では統計の更新(ANALYZE)と、必要なら明示ヒント(broadcast(df) など)で戦略を固定するのが定石です。

シャッフルハッシュ結合:両表を結合キーで再分配する

両方の表が大きく、どちらもブロードキャストできないときの基本形がシャッフルハッシュ結合(shuffle hash join)、Hive系ではリパーティション結合とも呼ばれます。考え方は単純で、両表を結合キーのハッシュで同じ規則に従って再分配し、同じキーの行が必ず同じノードへ集まるようにしてから、各ノード内でローカルにハッシュ結合します。

両表とも partition = hash(結合キー) mod N で再分配(N はノード/パーティション数)
  key=a の行 → L からも R からも同じノードNx へ
  key=b の行 → L からも R からも同じノードNy へ
各ノード: 自分に集まった L 断片から一方のハッシュ表を作り、
          もう一方の断片を lookup して結合

このとき決定的なのは、両表に同一のハッシュ関数と同一の分割数を適用すること。そうして初めて「hash(a) が指すノード」が両表で一致し、キー a の行が漏れなく同じノードに揃います。ローカル結合フェーズでは、集まった断片のうち小さい側でハッシュ表を作り、大きい側でプローブするのが定石です。コストの本体は、/data-engineering/spark-rdd-dag/ でいうワイド依存=シャッフル、つまり両表ぶんの全対全転送にあります。ブロードキャストが片側だけを動かすのに対し、シャッフルは両側を動かすぶん高くつきます。

ソートマージ結合:ソートしてから2本のストリームを突き合わせる

シャッフルハッシュ結合には弱点があります。ローカル結合フェーズで片方の断片からハッシュ表を作るため、その断片がノードのメモリに載らないと破綻する(スピルしても効率が落ちる)点です。結合キーが偏って一部ノードに巨大な断片が来たり、そもそも両表とも巨大だったりすると、これが起きます。そこで大規模結合の既定として広く使われるのが**ソートマージ結合(sort-merge join)**です。

手順は三段です。(1) 両表を結合キーでシャッフル再分配して同じキーを同じノードへ集める(ここまではシャッフルハッシュと同じ)。(2) 各ノードで、集まった両表の断片をそれぞれ結合キーでソートする。(3) ソート済みの2本のストリームを、2つのポインタで同時に前進させながら突き合わせる(マージ)

ソート後(両表とも結合キー昇順):
  L: a a b d e …      ポインタ pL, pR を進めながら比較
  R: a b b c e …
   pL=a, pR=a → 一致(キーa の全組を出力)
   一致キーを出し切ったら、小さい方のポインタを前進
   pL の値 < pR の値 なら pL を進め、逆なら pR を進める

ソートマージの利点は、照合が両ストリームを1回ずつ順に舐めるだけで完結し、巨大なハッシュ表をメモリに常駐させずに済むこと。ソート自体はメモリを超えれば外部マージソートでディスクへスピルでき、大規模データやスキューに対して安定して動きます。さらに、結合キーでソートされた出力もソート済みになるため、後続の集約やウィンドウ関数、次の結合がそのソート順を再利用でき、追加のシャッフルを省けることがあります。Spark SQLがハッシュ結合よりソートマージを大表どうしの既定に据えているのは、この安定性とスピル耐性のためです。

戦略動かす表ローカル結合の方式メモリ前提向く条件
ブロードキャストハッシュ小表のみ全複製(大表は不動)メモリ上ハッシュ表へlookup小表のハッシュ表が全ノードに載る片方が閾値以下に十分小さい
シャッフルハッシュ両表をキーで再分配断片からハッシュ表を作りプローブ各ノードの片側断片がメモリに載る両表が大きいがハッシュ表は収まる
ソートマージ両表をキーで再分配両ソート済み列をマージ走査ソートはスピル可、常駐ハッシュ表不要超大規模・スキュー・出力ソート順を再利用したい

結合キーの偏り(skew):分散結合を殺す最大要因

戦略を正しく選んでも、**結合キーの偏り(data skew)**が全体を台無しにします。シャッフル系はどちらも hash(結合キー) mod N で行き先を決めるため、特定キーに行が極端に集中する(ホットキー)と、そのキーを担当する1ノードに両表の該当行が山と集まります。他ノードが早々に終わっても、その1ノードだけが巨大な結合を1台で背負い、ジョブ全体がそれを待つ——/data-engineering/mapreduce-shuffle/ のホットキー問題が、結合では両表ぶん効いてさらに悪化します。

ホットキー・NULLキー・直積の三重苦

分散結合の偏りには典型パターンがあります。第一にホットキー(人気商品ID、特定テナント、unknown などの既定値)に行が集中し、単一ノードのメモリ・時間を食い潰す。第二にNULLキーで、ON a.k = b.k で両表のNULLが同じ宛先へ集まり巨大な塊になる(結合条件上はNULL同士はマッチしないのに再分配だけされる無駄)。第三に、そのホットキーが両表に多数あると、そのノード内でローカルに近い直積(cross product)が発生し、出力行数が爆発する。対策は、ホットキーへソルトkey#0key#n に割ってから結合し後で戻す)を付けて複数ノードへ散らす、NULLは事前に除外またはランダム値へ振る、偏るキーだけ別処理にする、といった偏りを前提にした結合設計です。偏りは計算量ではなく再分配の分配で効くので、ノードを増やしても解決しません。

どれが選ばれるか:コストベースの判断基準

現代のエンジン(Spark SQL、各種MPP、Presto/Trino)は、これらを**コストベースオプティマイザ(CBO)**が統計を見て選びます。判断の骨子は次の順です。

  1. 片方がブロードキャスト閾値以下か。小さい表があり、その推定サイズが閾値(例10MB)以下ならブロードキャストハッシュ結合。全対全を回避できるので最優先。
  2. 両表が結合キーで事前配置済みか。両表が同じキー・同じ数のバケット/data-engineering/partitioning-bucketing/)や、MPPの同じ分散キー/data-engineering/mpp-data-warehouse/ のコロケーテッド結合)に配置されていれば、シャッフル自体を省いてノード内で直接結合できる。設計で稼ぐ最大の勝ち筋。
  3. 上のどちらでもなければシャッフル系。両表を再分配したうえで、ハッシュ表が載るならシャッフルハッシュ、超大規模・スキュー耐性・出力ソート順の再利用を狙うならソートマージ。多くのエンジンが安定性からソートマージを大表どうしの既定にする。
設計レビュー・試験の頻出論点

押さえる点。(1) 分散結合のコストは結合アルゴリズムより再分配(データ移動)で決まる。同じキーを同じノードへ集める必要があるため。(2) ブロードキャスト=小表を全ノード複製・大表は不動でシャッフルが片側で済む/シャッフルハッシュ=両表を hash(key) mod N で再分配し断片からハッシュ表/ソートマージ=再分配後に両表をソートしマージ走査。(3) ソートマージが大表の既定なのは常駐ハッシュ表が不要でスピルに強く、出力がソート済みだから。(4) 選択はコストベース——閾値以下ならブロードキャスト、事前配置(同一バケット/同一分散キー)ならシャッフル省略、他はシャッフル系。(5) 最大の落とし穴は結合キーの偏り(ホットキー・NULL・直積爆発)で、hash mod N の均等分割が一様分布を仮定するため崩れる。ノード増でなくソルト等の偏り対策で解く。「ブロードキャストは常に速い」ではなく小表のメモリ常駐が前提、という切り分けが要点。

まとめ

  • 分散結合の本質は照合すべき行を同じノードへ集める再分配で、コストの大半はこのデータ移動にある。アルゴリズムは三つの再分配戦略に集約される。
  • ブロードキャストハッシュ結合は小表を全ノードへ複製して大表を動かさないため、片側のブロードキャストだけで済む。前提は複製した小表のハッシュ表が各ノードのメモリに載ること(閾値判定)。
  • シャッフルハッシュ結合は両表を hash(結合キー) mod N で再分配し、同じキーを同じノードへ集めてローカルにハッシュ結合する。両表ぶんの全対全転送が本体コスト。
  • ソートマージ結合は再分配後に両表をキーでソートし、2本のソート済みストリームをマージ走査する。常駐ハッシュ表が要らずスピルに強く、出力もソート済みなので、大表どうしの既定として広く使われる。
  • 戦略はコストベースで選ばれる。閾値以下ならブロードキャスト、同一バケット/同一分散キーに事前配置していればシャッフルを省略、他はシャッフル系(安定性からソートマージが既定になりやすい)。
  • 最大の敵は結合キーの偏り。ホットキー・NULLキー・直積爆発が単一ノードを潰し、hash mod N の均等分割は一様分布の仮定に立つため現実データで崩れる。ノード増ではなくソルトやNULL除外など偏り前提の設計で解く。

データ工学 Article

分散結合戦略(broadcast・shuffle・sort-merge)を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

分散結合

比較で見る軸

難易度: advanced / カテゴリ: データ工学 / タグ数: 6

導入後に効く点

ソートマージ結合はシャッフル後に両表を結合キーでソートし、2本のソート済みストリームを同時走査(マージ)して照合する。ハッシュ表がメモリに載らない大規模結合やスピルに強く、多くのエンジンで大表どうしの既定になる。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
データ工学
タグ数
6

判断チェックリスト

  • 自社の用途が「分散結合 / シャッフル」に近いか確認する。
  • 強みである「分散結合の骨格は三つ。ブロードキャストハッシュ結合は小さい方の表を全ノードへ複製し、大表をローカルでハッシュ照合するのでシャッフルが片側で済む。両表が大きいときはシャッフル結合で結合キーのハッシュにより両表を再分配し、同じキーを同じノードへ集めてから結合する。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

分散結合シャッフルブロードキャスト結合ソートマージデータスキュー分散結合シャッフルブロードキャスト結合