CASE STUDIES LIST/ HOME
← Case #15#16 / 25Case #17 →
CASE STUDY #16Phase 4: Spark & Distributed ProcessingCLASSIFICATION: EXPERIMENT

Most Workers Finished Fast. The Last Worker Took Forever.

Mitigating Data Skew in PySpark Using Salting Techniques

Apache SparkPySparkSpark UI

1. The Problem

In a multi-tenant dataset, a single enterprise tenant owned 40% of all task records. Joining by `tenant_id` routed all 40% records to a single executor task, creating a 25-minute straggler.

2. What I Initially Thought

"I thought adding more cluster nodes would speed up the pipeline. But adding nodes didn't help because a single partition key cannot be split across multiple executors by default."

3. What I Learned

Data skew occurs when partition key values are unevenly distributed. Salting appends a random integer (`0-N`) to skew keys on the fact table, distributing hot keys evenly across multiple workers.

Data Skew & StragglersSalt KeysKey Distribution UniformityPartition Spill

4. What I Built

Salting transformation pipeline appending random salt keys `(0..7)` to skewed tenant keys, exploding dimension tables, and performing balanced parallel joins.

# Append random salt (0-7) to skewed fact keys
salted_fact = fact_df.withColumn("salt", (rand() * 8).cast("int")) \
                      .withColumn("salted_tenant_id", concat(col("tenant_id"), lit("_"), col("salt")))

# Explode dimension table to match salt range
salted_dim = dim_df.withColumn("salt_array", array([lit(i) for i in range(8)])) \
                    .withColumn("salt", explode("salt_array")) \
                    .withColumn("salted_tenant_id", concat(col("tenant_id"), lit("_"), col("salt")))

# Join on salted key -> Balanced partition distribution!
skew_free_df = salted_fact.join(salted_dim, "salted_tenant_id")

5. The Experiment

BEFORE

Joining skewed dataset without salting. 199 tasks completed in 12s; 1 task straggler ran for 25.4 minutes.

CHANGE APPLIED

Applied 8-way key salting transformation to distribute hot tenant records evenly across executors.

AFTER RESULT

Straggler task eliminated completely; maximum task duration dropped from 25.4 minutes to 34 seconds.

6. What Went Wrong

Exploded dimension table without filtering, increasing dimension row count unnecessarily for non-skewed tenant keys.

7. Engineering Decision & Trade-offs

Applied salting conditionally only to top 1% high-volume tenant keys identified in metadata profiling.

8. What I Would Do Differently in Production

In Spark 3.x, enable `spark.sql.adaptive.skewJoin.enabled=true` to allow Spark AQE to automatically split skewed partitions at runtime.

Questions I Can Now Answer Confidently in an Interview:

  • What causes data skew in distributed processing frameworks like Apache Spark?
  • How does the salting technique eliminate straggler tasks during wide join operations?
  • How does Spark 3.x Adaptive Query Execution (AQE) automatically handle skewed joins?

Expected / Verified Evidence

•Spark UI Task execution duration distribution histogram (showing straggler elimination)
•PySpark salting implementation script (pipelines/silver/salting_skew.py)
•Benchmark execution time metrics table
BACK TO ALL CASE STUDIESNEXT: CASE #17 (I Added .cache() and Made the Pipeline Slower)