Databricks Certified Data Engineer Associate 教科書
第3章 データ変換とモデリング(Data Transformation and Modeling, 22%)
🎯 この節の学習目標
spark.sql.shuffle.partitions・spark.default.parallelism・executor/driver メモリ・spark.sql.autoBroadcastJoinThreshold の意味と既定値を説明できる3-2 で見たとおり、結合や集約(groupBy)では、同じキーの行を同じワーカーに集めるシャッフルが発生します。シャッフル後のデータはパーティションという単位に分割され、パーティション1つが処理タスク1つに対応します。つまり「パーティション数=並列度と1タスクあたりのデータ量を決めるダイヤル」であり、本節のパラメータの多くはこのダイヤルの調整です。
大原則を先に述べます。チューニングは計測とセットです。パラメータを変えたら Spark UI やジョブの実行時間で効果を再計測し、改善しなければ戻す。「とりあえず値を変えて放置」は、データ量が変わった半年後に別の問題を引き起こします。
シャッフル後に作られるパーティションの数です。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;
RDD 系 API の既定並列度です(既定値はクラスタの総コア数などから決まります)。名前が似ていて混同しやすいのですが、DataFrame/SQL のシャッフル並列度を決めるのは spark.sql.shuffle.partitions の方です。DataFrame 中心の現在の開発でこの値を触る場面は限られますが、試験ではこの「どちらが何に効くか」の区別が問われます。
| パラメータ | 効く対象 | 既定値 |
|---|---|---|
spark.sql.shuffle.partitions | DataFrame / Spark SQL のシャッフル後パーティション数 | 200 |
spark.default.parallelism | RDD 系 API(join・reduceByKey 等)の既定パーティション数 | クラスタの総コア数に依存 |
各 executor(ワーカー上の実行プロセス)とドライバに割り当てるメモリ量です。Databricks ではクラスタのインスタンスタイプ選択でほぼ決まるため直接指定する場面は少ないものの、意味の理解は必須です。
collect() で大量データをドライバに集めた、巨大テーブルを broadcast した、などでドライバが OOM。対処はまずコード側の見直し(collect をやめる、broadcast 対象を見直す)結合時に「このサイズ以下のテーブルは自動で 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) # 無効化
試験でも実務でも、「この症状のとき何を変えるか」という形で問われます。
| 症状 | 原因の見立て | 打ち手 |
|---|---|---|
| シャッフル後に数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 を調整 |
ここまで手動チューニングを説明してきましたが、現在の Spark / Databricks では AQE(Adaptive Query Execution)が既定で有効であり、実行時の統計を見ながら多くを自動調整します。
図:AQE による実行時の再最適化
つまり、shuffle.partitions の「多すぎる」側の問題や、broadcast 判断の多くは AQE が吸収してくれます。それでも本節の知識が必要な理由は次の3つです。
shuffle.partitions は AQE にとっても初期値(上限の目安)として意味を持つ📝 試験のポイント
数字の暗記ポイントは2つ:spark.sql.shuffle.partitions の既定は 200、spark.sql.autoBroadcastJoinThreshold の既定は 10MB(-1 で無効化)。区別の暗記ポイントは1つ:DataFrame/SQL のシャッフルには shuffle.partitions、RDD には default.parallelism。そして姿勢の問題として「変更したら再計測する」「AQE が有効な環境ではまず AQE に任せ、問題が残る場合に手動調整する」が正解側の考え方です。
✅ この節のまとめ
spark.sql.shuffle.partitions(既定 200)は DataFrame/SQL のシャッフル後パーティション数。小データでは減らし、大データでは増やす。spark.default.parallelism は RDD 系 API の既定並列度。DataFrame のシャッフルには効かない。spark.executor.memory/spark.driver.memory は実行プロセスのメモリ。OOM はメモリ増強だけでなく、パーティション分割やコード(collect・broadcast)の見直しで解決できることが多い。spark.sql.autoBroadcastJoinThreshold(既定 10MB)以下のテーブルは自動 broadcast。-1 で無効化。大テーブルの誤 broadcast は OOM のもと。問1. spark.sql.shuffle.partitions の説明として正しいものはどれか。
正解:A
spark.sql.shuffle.partitions は結合・集約などのシャッフル後に作られるパーティション数で、既定は一律 200 です。Bは spark.default.parallelism、Cは spark.sql.autoBroadcastJoinThreshold の説明です。Dの読み込み時の分割はファイルサイズや maxPartitionBytes 系の設定で決まり、このパラメータの対象ではありません。
問2. 小規模なデータ(数百MB)の集計ジョブで、シャッフル後に数KB程度のタスクが200個生成され、タスク起動のオーバーヘッドで遅くなっている。AQE が無効の環境での最も直接的な対処はどれか。
spark.sql.shuffle.partitions を減らすspark.sql.shuffle.partitions を増やすspark.driver.memory を増やすspark.sql.autoBroadcastJoinThreshold を -1 にする正解:A
「小さすぎるタスクが多数」はデータ量に対してシャッフルパーティションが多すぎるサインで、shuffle.partitions を減らして1タスクあたりの処理量を適正化します(AQE が有効なら自動 coalesce が同じことをしてくれます)。Bは逆方向で悪化します。Cはドライバのメモリの話であり、タスクの粒度とは無関係です。Dは broadcast join の自動適用を止める設定で、症状と関係ありません。
問3. 実行計画を確認すると、実際には数GBあるテーブルが BroadcastHashJoin の broadcast 側に選ばれており、executor の OOM が発生している。最も適切な対処はどれか。
spark.sql.autoBroadcastJoinThreshold を -1 に設定するか閾値を下げ、このテーブルが broadcast されないようにするspark.sql.autoBroadcastJoinThreshold を 1GB に引き上げるspark.default.parallelism を増やすspark.sql.shuffle.partitions を 200 のまま維持する正解:A
大きなテーブルの broadcast は全ワーカーにその全量を配ることを意味し、OOM の典型原因です。閾値を下げるか -1 で自動 broadcast を無効化し、shuffle join に戻すのが正しい対処です。Bは閾値を上げる方向で、より大きなテーブルまで broadcast 対象になり悪化します。Cは RDD 系の並列度で、この結合戦略の問題には効きません。Dは何もしないのと同じで対処になっていません。
問4. AQE(Adaptive Query Execution)が自動的に行う最適化として正しくないものはどれか。
正解:D
ワーカーノード数の増減はクラスタのオートスケーリングの機能であり、AQE の役割ではありません。AQE はあくまで「実行中のクエリの計画」を実行時統計で再最適化する仕組みで、A(パーティションの自動結合)、B(join 戦略の動的切替)、C(スキューパーティションの分割)がその3本柱です。この区別(クエリ計画の最適化 vs 計算資源のスケーリング)を押さえておきましょう。