第3章 データ変換とモデリング / 想定学習時間:30〜40分 / 最終確認:2026年8月

3-5. 基本チューニングパラメータ(shuffle.partitions・parallelism・memory・broadcastJoinThreshold)

🎯 この節の学習目標

1. チューニングの前提:シャッフルとパーティション

3-2 で見たとおり、結合や集約(groupBy)では、同じキーの行を同じワーカーに集めるシャッフルが発生します。シャッフル後のデータはパーティションという単位に分割され、パーティション1つが処理タスク1つに対応します。つまり「パーティション数=並列度と1タスクあたりのデータ量を決めるダイヤル」であり、本節のパラメータの多くはこのダイヤルの調整です。

大原則を先に述べます。チューニングは計測とセットです。パラメータを変えたら Spark UI やジョブの実行時間で効果を再計測し、改善しなければ戻す。「とりあえず値を変えて放置」は、データ量が変わった半年後に別の問題を引き起こします。

2. 4つの基本パラメータ

2-1. spark.sql.shuffle.partitions(既定:200)

シャッフル後に作られるパーティションの数です。DataFrame/SQL の結合・集約の後の並列度を決めます。既定値は 200 で、データ量に関係なく一律です。

# 現在値の確認と変更(PySpark)
spark.conf.get("spark.sql.shuffle.partitions")   # '200'
spark.conf.set("spark.sql.shuffle.partitions", 64)
-- SQL でも設定できる
SET spark.sql.shuffle.partitions = 64;

2-2. spark.default.parallelism

RDD 系 API の既定並列度です(既定値はクラスタの総コア数などから決まります)。名前が似ていて混同しやすいのですが、DataFrame/SQL のシャッフル並列度を決めるのは spark.sql.shuffle.partitions の方です。DataFrame 中心の現在の開発でこの値を触る場面は限られますが、試験ではこの「どちらが何に効くか」の区別が問われます。

パラメータ効く対象既定値
spark.sql.shuffle.partitionsDataFrame / Spark SQL のシャッフル後パーティション数200
spark.default.parallelismRDD 系 API(join・reduceByKey 等)の既定パーティション数クラスタの総コア数に依存

2-3. spark.executor.memory / spark.driver.memory

executor(ワーカー上の実行プロセス)ドライバに割り当てるメモリ量です。Databricks ではクラスタのインスタンスタイプ選択でほぼ決まるため直接指定する場面は少ないものの、意味の理解は必須です。

2-4. spark.sql.autoBroadcastJoinThreshold(既定:10MB)

結合時に「このサイズ以下のテーブルは自動で broadcast join にする」という閾値です(3-2 の復習:broadcast join は小テーブルを全ワーカーに配ってシャッフルを回避する方式)。-1 を設定すると自動 broadcast を無効化できます。

spark.conf.set("spark.sql.autoBroadcastJoinThreshold", 50 * 1024 * 1024)  # 50MB
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)                # 無効化

3. 症状→パラメータの対応表

試験でも実務でも、「この症状のとき何を変えるか」という形で問われます。

症状原因の見立て打ち手
シャッフル後に数KB程度の小さいタスクが200個並び、オーバーヘッドが目立つデータ量に対して shuffle.partitions が過剰spark.sql.shuffle.partitions減らす(または AQE に任せる)
シャッフルを伴う処理でタスクの OOM・大量のディスクスピル1パーティションが大きすぎる/executor メモリ不足shuffle.partitions増やす、またはワーカーのメモリ増強
結合のたびにドライバや executor が OOMし、実行計画に BroadcastHashJoin が出ている実際は大きいテーブルが誤って broadcast されているautoBroadcastJoinThreshold下げる or -1 で無効化
小さいマスタとの結合なのに毎回シャッフルしているマスタが閾値超で broadcast されていない閾値を上げるか、broadcast() ヒントで明示(3-2)
collect() の実行でドライバが OOM全データをドライバ1台に集めているコードを見直す(collect をやめる)。driver.memory 増強は対症療法
RDD API の処理だけ並列度が低いRDD には shuffle.partitions が効かないspark.default.parallelism を調整

4. AQE(Adaptive Query Execution):多くは自動化されている

ここまで手動チューニングを説明してきましたが、現在の Spark / Databricks では AQE(Adaptive Query Execution)が既定で有効であり、実行時の統計を見ながら多くを自動調整します。

クエリ実行開始静的な実行計画でスタート
ステージ完了ごとに実際のデータサイズを観測
AQE が実行時に計画を再最適化① 小さすぎるシャッフルパーティションを自動結合(coalesce)
② 実サイズが小さいと判明した側を broadcast join に切替
③ スキュー(偏った)パーティションを自動分割
最適化された計画で残りを実行

図:AQE による実行時の再最適化

つまり、shuffle.partitions の「多すぎる」側の問題や、broadcast 判断の多くは AQE が吸収してくれます。それでも本節の知識が必要な理由は次の3つです。

📝 試験のポイント

数字の暗記ポイントは2つ:spark.sql.shuffle.partitions の既定は 200spark.sql.autoBroadcastJoinThreshold の既定は 10MB(-1 で無効化)。区別の暗記ポイントは1つ:DataFrame/SQL のシャッフルには shuffle.partitions、RDD には default.parallelism。そして姿勢の問題として「変更したら再計測する」「AQE が有効な環境ではまず AQE に任せ、問題が残る場合に手動調整する」が正解側の考え方です。

✅ この節のまとめ

練習問題

問1. spark.sql.shuffle.partitions の説明として正しいものはどれか。

  1. DataFrame や Spark SQL でシャッフルが発生した後のパーティション数を制御し、既定値は 200 である
  2. RDD API の既定並列度を制御し、既定値はクラスタの総コア数である
  3. broadcast join を適用するテーブルサイズの閾値であり、既定値は 10MB である
  4. ソースファイルを読み込む際の入力パーティション数を制御する
解答と解説を見る

正解:A

spark.sql.shuffle.partitions は結合・集約などのシャッフル後に作られるパーティション数で、既定は一律 200 です。Bは spark.default.parallelism、Cは spark.sql.autoBroadcastJoinThreshold の説明です。Dの読み込み時の分割はファイルサイズや maxPartitionBytes 系の設定で決まり、このパラメータの対象ではありません。

問2. 小規模なデータ(数百MB)の集計ジョブで、シャッフル後に数KB程度のタスクが200個生成され、タスク起動のオーバーヘッドで遅くなっている。AQE が無効の環境での最も直接的な対処はどれか。

  1. spark.sql.shuffle.partitions を減らす
  2. spark.sql.shuffle.partitions を増やす
  3. spark.driver.memory を増やす
  4. spark.sql.autoBroadcastJoinThreshold を -1 にする
解答と解説を見る

正解:A

「小さすぎるタスクが多数」はデータ量に対してシャッフルパーティションが多すぎるサインで、shuffle.partitions を減らして1タスクあたりの処理量を適正化します(AQE が有効なら自動 coalesce が同じことをしてくれます)。Bは逆方向で悪化します。Cはドライバのメモリの話であり、タスクの粒度とは無関係です。Dは broadcast join の自動適用を止める設定で、症状と関係ありません。

問3. 実行計画を確認すると、実際には数GBあるテーブルが BroadcastHashJoin の broadcast 側に選ばれており、executor の OOM が発生している。最も適切な対処はどれか。

  1. spark.sql.autoBroadcastJoinThreshold を -1 に設定するか閾値を下げ、このテーブルが broadcast されないようにする
  2. spark.sql.autoBroadcastJoinThreshold を 1GB に引き上げる
  3. spark.default.parallelism を増やす
  4. spark.sql.shuffle.partitions を 200 のまま維持する
解答と解説を見る

正解:A

大きなテーブルの broadcast は全ワーカーにその全量を配ることを意味し、OOM の典型原因です。閾値を下げるか -1 で自動 broadcast を無効化し、shuffle join に戻すのが正しい対処です。Bは閾値を上げる方向で、より大きなテーブルまで broadcast 対象になり悪化します。Cは RDD 系の並列度で、この結合戦略の問題には効きません。Dは何もしないのと同じで対処になっていません。

問4. AQE(Adaptive Query Execution)が自動的に行う最適化として正しくないものはどれか。

  1. 実行時の統計に基づき、小さすぎるシャッフルパーティションを結合(coalesce)する
  2. 実行時に判明したテーブルサイズに基づき、shuffle join を broadcast join に切り替える
  3. 偏り(スキュー)のある大きなパーティションを分割して処理する
  4. クラスタのワーカーノード数を自動的に増減させる
解答と解説を見る

正解:D

ワーカーノード数の増減はクラスタのオートスケーリングの機能であり、AQE の役割ではありません。AQE はあくまで「実行中のクエリの計画」を実行時統計で再最適化する仕組みで、A(パーティションの自動結合)、B(join 戦略の動的切替)、C(スキューパーティションの分割)がその3本柱です。この区別(クエリ計画の最適化 vs 計算資源のスケーリング)を押さえておきましょう。