Aidp Spark Optimization

作者 oracle-samples90b42d6c24d4無授權條款收錄於 2026年10月8日更新於 2026年10月8日

Use when a Spark job/notebook is slow, missing an SLA, spilling, OOMing, generating too many small files, or shuffling/skewing heavily; when reviewing Spark/PySpark code or a Spark UI for performance; or before running a large Spark workload. Covers open-source Apache Spark 3.5.0 (+ Delta Lake) tuning -- partitions, shuffle, joins, skew, file layout, memory, codegen, caching, AQE, compression, and configuration.

AI 產生的概覽

指導 Apache Spark 3.5.0 效能調校:分割區、shuffle、join、資料傾斜、記憶體、檔案配置、AQE 與 Delta Lake。

功能
此技能是一份針對開源 Apache Spark 3.5.0 與 Delta Lake 工作負載的調校參考指南。它會依主要症狀(join 緩慢、溢寫、小檔案、平行度不足、CPU 密集聚合、重複讀取)導向對應的參考文件,並提供依影響排序的高效益技巧,包含設定、適用模式、反模式與效果證據。它也提供量測流程(偵測、診斷、提案、套用、重跑、比較)以及常見錯誤,例如比較不等價的兩次執行,或誤以為僅能在叢集建立時設定的設定已生效。
適用情境
當 Spark 作業或筆記本執行緩慢、未達 SLA、發生溢寫或 OOM、產生大量小檔案,或 shuffle 與資料傾斜嚴重時使用。也適合用來檢視 Spark 或 PySpark 程式碼與 Spark UI 的效能表現,以及在啟動大型 Spark 工作負載前先做準備。
執行需求
不需要指令碼,僅有說明與參考文件。前提是可存取 Apache Spark 3.5.0(可選 Delta Lake 3.2.0)以及讀取 Spark UI 指標的方式;部分範例涉及 Oracle AI Data Platform 及用於指標、叢集維運與 DDL 的搭配技能。

Spark Optimization

Field-tested techniques for optimizing open-source Apache Spark 3.5.0 (and open-source Delta Lake) workloads. Every technique lists what it does, why it matters, patterns (when it helps), anti-patterns (when it does not help or hurts), the exact config/code, and impact evidence from real reproductions.

Applies to plain OSS Spark 3.5.0. Vendor-only features (Databricks Photon / predictive optimization / Delta disk cache, AWS Glue/EMR runtime tricks) are excluded or explicitly flagged. (Note: Delta Lake liquid clustering, OPTIMIZE/ZORDER, deletion vectors, CDF are open-source — GA in Delta 3.2.0 — see references/08-delta-lake.md.) Some examples run on the Oracle AI Data Platform (AIDP); AIDP-specific execution rules are in references/aidp-notes.md.

In this plugin (oracle-ai-data-platform-workbench-engineer-agent): measure/apply on AIDP via the bundled scripts/aidp_sql.py (one SparkSession per cluster -- set/revert spark.conf explicitly; see references/aidp-notes.md); pull Spark-UI stage/task metrics via the aidp-spark-debugging skill; right-size compute + set cluster-create-only configs (e.g. spark.memory.fraction) via aidp-cluster-ops; run Delta OPTIMIZE/VACUUM/ZORDER DDL via aidp-sql-ddl / aidp-table-management. Adapted from the ai-data-engineer-agent spark-optimization skill (Oracle).

Core principle

Optimization is a measurement loop, not a guess. Detect → diagnose → propose → apply → re-run on the same data → compare the same metrics.

Most Spark time is lost to moving data (shuffle), waiting on a straggler (skew), spilling (under-memory), doing redundant work (re-reads, re-materialization, repeated actions), or per-row execution overhead (wide codegen). Almost every win below reduces one of those.

When to use

  • A job/notebook is slow, missing an SLA, or its cost is too high.
  • Spark UI shows: a single slow stage, task p100/p50 > 2x skew, large shuffle read/write, memory/disk spill, high GC, or thousands of tiny tasks/files.
  • You see code smells: union of the same table, a driver loop calling collect()/head()/count() repeatedly, MERGE on a huge table, wide groupBy (100+ fields), reading 100k+ small files, an un-filtered join with a big dimension.
  • You read from / write to an Oracle database (ADW/ATP/Exadata): a single-task JDBC read, a slow or redo-saturating multi-TB write, or unsupported array/map/struct columns. (references/09-oracle-database.md)
  • Before launching a large ingest/transform so the cluster + configs are right the first time.

When NOT to use: correctness bugs (use debugging), or sub-second jobs where tuning effort exceeds the payoff. Structured Streaming engine tuning (trigger interval, maxOffsetsPerTrigger, state store) is out of scope here — but each micro-batch is batch-shaped, so the join/skew/partition/file/codegen techniques below apply per batch.

How to find the opportunity → which reference to read

dot
digraph route {  rankdir=LR; node [shape=box];  sym [shape=diamond, label="Dominant symptom?"];  sym -> "references/diagnosis.md" [label="not sure / need to measure"];  sym -> "references/02-joins.md" [label="slow join, skew, SortMergeJoin"];  sym -> "references/04-memory-and-spill.md" [label="spill, OOM, lost executors, GC"];  sym -> "references/cluster-sizing.md" [label="right-size compute: workers/OCPU/RAM"];  sym -> "references/03-file-layout-io.md" [label="many small files, slow scan, listing"];  sym -> "references/01-partitioning.md" [label="too many/few partitions, weak parallelism"];  sym -> "references/05-codegen.md" [label="CPU-bound wide aggregation"];  sym -> "references/06-caching-materialization.md" [label="re-reads, union, driver loop, MERGE"];  sym -> "references/07-aqe.md" [label="want runtime adaptivity"];  sym -> "references/08-delta-lake.md" [label="Delta table: small files, OPTIMIZE/ZORDER/clustering, VACUUM, deletion vectors, CDF"];  sym -> "references/09-oracle-database.md" [label="read/write Oracle DB / ADW / Exadata (JDBC parallelism, redo, complex types)"];}

Then consult references/config-matrix.md for the exact key, default, impact, and where it can be set (notebook / cluster-create-only / non-modifiable), and references/quick-reference.md for the impact-ranked checklist.

Reference index

FileCovers
references/diagnosis.mdHow to find & measure opportunities from the Spark UI: symptom→cause, skew ratio, which metrics, query→stage timing.
references/01-partitioning.mdPartition counts, parallelism, shuffle.partitions, AQE coalescing, tiny/empty partitions, repartition vs coalesce.
references/02-joins.mdBroadcast join, Shuffle-Hash vs Sort-Merge, skew handling, semi-join pre-filter, salting.
references/03-file-layout-io.mdSmall-file problem, openCostInBytes/maxPartitionBytes, compaction/OPTIMIZE, partitionOverwriteMode, gzip splittability, compression (zstd).
references/04-memory-and-spill.mdSpark memory model, memory.fraction, spill detection/fix, off-heap, the gzip-4x rule.
references/cluster-sizing.mdRight-size AIDP compute: workers x OCPU x RAM, parallelism vs memory, observed-run → recommendation.
references/05-codegen.mdWholeStage codegen, codegen.maxFields, when generated code is slower.
references/06-caching-materialization.mdCaching & cache layout, avoid unnecessary materialization, union-of-same-table, driver-loop, JOIN-over-MERGE.
references/07-aqe.mdAdaptive Query Execution: coalesce, skew join, the threshold interplay.
references/08-delta-lake.mdDelta Lake 3.2.0: OPTIMIZE/compaction (+VACUUM dependency), optimized writes, auto-compaction, ZORDER, liquid clustering, deletion vectors, CDF, data skipping, file sizing; the optimizeWrite+zstd+binSize recipe.
references/09-oracle-database.mdOracle DB (ADW/ATP/Exadata): parallel JDBC reads (partitionColumn, fetchsize), bulk (COPY_DATA, ADW-only) vs conventional-JDBC writes, the redo-log / NOLOGGING field case + tradeoffs, complex types (JSON-as-VARCHAR2), Storage Partition Join.
references/config-matrix.mdMaster config table: default, impact, and where-settable classification.
references/case-studies.mdReal before/after numbers (field engagements + AIDP reproductions).
references/quick-reference.mdImpact-ranked checklist + symptom→technique lookup.
references/aidp-notes.mdAIDP execution model + how to set/revert configs safely (one SparkSession per cluster) + collect-metrics-early.

The 80/20: highest-impact moves first

Ranked by typical payoff (full details + caveats in the referenced files):

  1. Eliminate avoidable shuffle on joins — raise spark.sql.autoBroadcastJoinThreshold so a small/medium side broadcasts; or semi-join pre-filter the big dimension down to broadcastable size. (02-joins.md)
  2. Fix the small-file problem — compact sources / size output files; tune maxPartitionBytes + openCostInBytes. Listing+opening 100k+ files can cost more than the data. (03-file-layout-io.md)
  3. Right-size memory to stop spill — raise spark.memory.fraction (cluster-create-only on AIDP) when there are no user data structures; spill to disk is a silent multiplier. (04-memory-and-spill.md, cluster-sizing.md)
  4. Address skew — AQE skew-join, or semi-join pre-filter + broadcast; a p100/p50 > 2x join stage serializes the whole stage on a straggler. (02-joins.md, 07-aqe.md)
  5. Avoid redundant work — don't union the same table, don't loop collect()/head() on the driver, treat intermediates as views (don't materialize), prefer JOIN over MERGE for full reloads. (06-caching-materialization.md)
  6. Compress shuffle/spill/output with zstd — spark.io.compression.codec=zstd + spark.sql.parquet.compression.codec=zstd: tight like gzip, fast like snappy; cuts spill-disk and output size. (03-file-layout-io.md)
  7. Tune parallelism — shuffle.partitions ≈ 2–3× total cores for large shuffles; pair with AQE coalescing to avoid small output files. (01-partitioning.md)
  8. Constrain codegen on very wide aggregations — lower spark.sql.codegen.maxFields when a wide groupBy is CPU-bound; generated code can be slower than the fallback. (05-codegen.md)

Workflow

  1. Measure — run the workload, collect stage metrics + task quantiles (diagnosis.md). On AIDP, see aidp-notes.md for collecting Spark UI data.
  2. Diagnose — read explain(True)/the SQL plan; map the dominant symptom to a technique.
  3. Propose — pick the technique; check config-matrix.md for where the config can be set.
  4. Apply — change code or config. On a shared cluster, remember: one SparkSession per cluster — a spark.conf.set leaks to other notebooks; revert it explicitly (aidp-notes.md).
  5. Re-run on the same cluster + data, prove the workload is logically identical (same rows/columns/result), and compare the same metrics (wall time, shuffle, spill, task skew).

Common mistakes

  • Comparing wall time of two runs that aren't logically identical (different data/cache state). Prove equivalence first.
  • Reading summed task metrics as wall-clock — stage duration is start→end timestamps; cumulative task time is summed across tasks.
  • Counting AQE-skipped stages as time spent.
  • repartition() "to be safe" — it forces a shuffle; only repartition with a reason (see 01-partitioning.md).
  • Lowering AQE skew/advisory partition size so far that you create a new small-file problem.
  • Setting a cluster-create-only config (e.g. spark.memory.fraction) from a notebook and assuming it took effect — it didn't. Verify with spark.conf.get / the Environment tab (config-matrix.md).

來源與署名

來源:oracle-samples/oracle-aidp-samples位於ai/claude-code-plugins/oracle-ai-data-platform-workbench-engineer-agent/skills/aidp-spark-optimization提交90b42d6

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 oracle-samples/oracle-aidp-samples 的技能