Sometimes when joining two big tables, some keys appear way more than others. This makes the join slow and uneven. Handling skewed joins helps balance the work and speed up the process.
Handling skewed joins in Apache Spark
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1) # Example of salting technique from pyspark.sql.functions import rand # Add a random salt to the skewed key (large table) skewed_df = df.withColumn("salt", (rand() * 10).cast("int")) # Create salt values for small table salts = spark.range(10).withColumnRenamed("id", "salt") # Cross join small table with all salts small_df = other_df.crossJoin(salts) # Join on key and salt joined_df = skewed_df.join(small_df, on=["key", "salt"])
Setting spark.sql.autoBroadcastJoinThreshold to -1 disables broadcast joins to force shuffle joins.
Salting adds a random number to the join key to spread out skewed keys across partitions.
# Disable broadcast join spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
# Add salt column to skewed dataframe from pyspark.sql.functions import rand skewed_df = df.withColumn("salt", (rand() * 10).cast("int"))
# Cross join non-skewed df with salt values salts = spark.range(10).withColumnRenamed("id", "salt") non_skewed_df = other_df.crossJoin(salts) # Join on key and salt joined_df = skewed_df.join(non_skewed_df, on=["key", "salt"])
This program creates a skewed dataset where key=1 appears 1000 times. It adds a salt column to spread the join load. The smaller dataframe is expanded with all salt values to match. The join is done on both key and salt to balance the work.
from pyspark.sql import SparkSession from pyspark.sql.functions import rand, expr spark = SparkSession.builder.appName("SkewedJoinExample").getOrCreate() # Create skewed dataframe with many rows for key=1 data1 = [(1, f"val_{i}") for i in range(1000)] + [(2, "val_1000")] # Create smaller dataframe data2 = [(1, "info_1"), (2, "info_2")] # Create DataFrames skewed_df = spark.createDataFrame(data1, ["key", "value"]) other_df = spark.createDataFrame(data2, ["key", "info"]) # Disable broadcast join to force shuffle join spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1) # Add salt column to skewed_df skewed_df = skewed_df.withColumn("salt", (rand() * 10).cast("int")) # Add salt column to other_df with fixed salt values (0 to 9) to join properly salt_values = spark.range(10).withColumnRenamed("id", "salt") other_df_salted = other_df.crossJoin(salt_values) # Join on key and salt joined_df = skewed_df.join(other_df_salted, on=["key", "salt"]) # Show count to verify join print(f"Joined rows count: {joined_df.count()}") spark.stop()
Salting works best when you know which keys are skewed.
Too many salt values increase data size and join time, so choose wisely.
Disabling broadcast join helps avoid uneven data distribution in skewed joins.
Skewed joins happen when some keys have many rows, causing slow joins.
Salting adds a random number to keys to spread data evenly across partitions.
Disabling broadcast joins can help force better join strategies for skewed data.
Practice
What is the main problem caused by skewed joins in Apache Spark?
Solution
Step 1: Understand skewed join definition
Skewed joins happen when some keys have a lot more rows than others, causing uneven data distribution.Step 2: Identify the impact on performance
This uneven distribution causes some tasks to take much longer, slowing down the entire join operation.Final Answer:
Some keys have many rows, causing slow join performance -> Option CQuick Check:
Skewed joins = slow join due to uneven keys [OK]
- Thinking skewed joins cause data duplication
- Confusing skew with memory errors
- Assuming all keys have equal rows
Which of the following is the correct way to add a salt column for handling skewed joins in Spark using PySpark?
from pyspark.sql.functions import rand, floor
# Add salt column
salted_df = df.withColumn('salt', floor(rand() * 10))
Solution
Step 1: Understand salt column creation
Salt column should be an integer from 0 to 9 to spread keys evenly.Step 2: Check the code correctness
Using floor(rand() * 10) creates integers 0-9, which is correct for salting.Final Answer:
salted_df = df.withColumn('salt', floor(rand() * 10)) -> Option AQuick Check:
floor(rand()*10) creates salt 0-9 [OK]
- Using rand() without floor gives float salt
- Adding 10 instead of multiplying
- Not converting to integer with floor
Given the following PySpark code snippet, what will be the output count of joined_df?
df1 = spark.createDataFrame([(1, 'A'), (1, 'B'), (2, 'C')], ['id', 'val1'])
df2 = spark.createDataFrame([(1, 'X'), (1, 'Y'), (3, 'Z')], ['id', 'val2'])
joined_df = df1.join(df2, 'id')
print(joined_df.count())
Solution
Step 1: Analyze join keys and rows
df1 has id=1 twice, df2 has id=1 twice, so join on id=1 produces 2*2=4 rows. id=2 and id=3 do not match both sides.Step 2: Calculate total joined rows
Only id=1 matches, producing 4 rows in joined_df.Final Answer:
4 -> Option BQuick Check:
2x2 matches for id=1 = 4 rows [OK]
- Counting only unique keys, ignoring duplicates
- Assuming join count equals smaller table size
- Ignoring multiple matches per key
Identify the error in the following PySpark code snippet intended to handle skewed joins by salting:
from pyspark.sql.functions import rand, floor
salted_df1 = df1.withColumn('salt', floor(rand() * 5))
salted_df2 = df2.withColumn('salt', floor(rand() * 5))
joined_df = salted_df1.join(salted_df2, ['id', 'salt'])
Solution
Step 1: Understand salting logic
Salt must be added consistently to both dataframes so matching keys have the same salt value.Step 2: Identify error in salt generation
Here, salt is generated independently with rand(), so salt values won't match for same keys, causing join to fail.Final Answer:
Salt columns are added independently, so keys may not match on salt -> Option DQuick Check:
Independent salt columns cause join mismatch [OK]
- Adding salt independently without coordination
- Joining only on 'id' when salting is used
- Misunderstanding rand() output range
You have two large datasets with a highly skewed join key. Which approach best handles the skew to improve join performance?
- Add a random salt column to the skewed dataset and replicate the smaller dataset across all salt values, then join on both key and salt.
- Disable broadcast joins to force shuffle join.
- Use
map-side joinwithout salting. - Increase executor memory without changing join logic.
Solution
Step 1: Understand skewed join handling
Salting spreads skewed keys across partitions by adding a random salt column to the skewed dataset and replicating the smaller dataset across all possible salt values.Step 2: Evaluate options
Disabling broadcast or increasing memory alone won't fix skew. Map-side join without salting won't handle skew properly.Final Answer:
Add random salt to skewed dataset and replicate smaller dataset across salt values, join on key and salt -> Option AQuick Check:
Random salt skewed + replicate small fixes skew [OK]
- Disabling broadcast join alone fixes skew
- Not replicating the smaller dataset when salting
- Relying only on memory increase
Ready to prove it?
Pass the test and this pattern moves unknown
