Skew Join Salting Key in Python (Demo)
Demonstrates skew join salting by expanding a smaller side with salt keys and matching rows on the larger side via random salt assignment.
Python code
47 linesimport random
def skew_join_salting_key(left_df, right_df, salt_range=4):
"""
Demonstrates skew join salting: expand the smaller side with salt keys,
then attach a salt key to each row on the larger side.
Returns a list of (left, right, salt) tuples.
"""
skewed_left = []
for row in left_df:
for salt in range(salt_range):
skewed_left.append((row, salt))
joined = []
for l_row, salt in skewed_left:
for r_row in right_df:
if r_row["key"] == l_row["key"] and r_row["salt"] == salt:
joined.append((l_row, r_row["value"], salt))
return joined
if __name__ == "__main__":
# Simulate a small 'right' side (dimension table) with prefixed salt keys
right_df = [
{"key": "A", "salt": 0, "value": "x"},
{"key": "A", "salt": 1, "value": "y"},
{"key": "B", "salt": 0, "value": "z"},
]
# Large left side: each row will pick a random salt in [0, salt_range)
left_df = [
{"key": "A", "id": 101},
{"key": "A", "id": 102},
{"key": "B", "id": 103},
]
# Assign a random salt to each left row (simulating a distributed join)
random.seed(42)
left_df_with_salt = []
for row in left_df:
row["salt"] = random.randrange(4)
left_df_with_salt.append(row)
result = skew_join_salting_key(left_df_with_salt, right_df)
for l, r, salt in result:
print(f"left_id={l['id']} key={l['key']} right_value={r} salt={salt}")
Output
left_id=101 key=A right_value=x salt=0
left_id=101 key=A right_value=y salt=1
left_id=102 key=A right_value=x salt=0
left_id=102 key=A right_value=y salt=1
left_id=103 key=B right_value=z salt=0
How it works
Skew join salting mitigates hot-key skew in distributed joins by adding a salt dimension to the smaller side and randomly assigning salts to rows on the larger side. The skew_join_salting_key expands the left (large) side with all salt values, then matches exact key+salt pairs against the pre-salted right side. Using random.seed(42) ensures reproducible salt assignments, so the output is deterministic. This mimics a real Spark-style salted join where shuffle keys are balanced across partitions. The approach trades extra memory for balanced compute distribution.
Common mistakes
- Forgetting to seed random for reproducible test output
- Assigning salts on the wrong side (should be the large side)
- Using a salt_range too small to actually reduce skew
- Mismatching salt values between the two sides
Variations
- Use `itertools.product` to generate salt-expanded rows more concisely
- Replace random assignment with a hash-based salt (e.g., `row['key'] % salt_range`) for stable bucketing
Real-world use cases
- Balancing joins between a huge fact table and a small dimension table in PySpark batch jobs.
- Reducing hot-key bottlenecks when aggregating user events by user_id in streaming pipelines.
- Preventing out-of-memory errors in distributed SQL engines during high-cardinality key joins.
Sponsored
More from Big data & Spark
Keep learning
Related tutorials and quizzes for this topic.