Efficiently Join a Large Dataset with a Small Lookup Table Using Spark Broadcast Joins
Speed up joins between a large dataset and a small lookup table in Spark by using broadcast joins. Learn how to set thresholds, apply hints, verify the plan, and recover from failures.
17 Sept 2026, 12:12 UTC

Desired Outcome
Speed up a join between a large DataFrame (10 GB+) and a small lookup table (≤ 100 MB) by avoiding the costly shuffle phase. The goal is to perform the join in broadcast‑hash‑join mode, keeping network traffic low and execution time short.
Prerequisites
- Apache Spark 3.x (or newer) running in a cluster with at least one executor.
- Knowledge of the DataFrame API in Scala, Python, or SQL.
- Access to the Spark UI (typically at
http://driver-host:4040). - Sufficient executor memory to hold the broadcasted table (e.g.,
--executor-memory 4G). - Understanding that broadcast joins are only supported for inner, left‑semi, and left‑anti joins.
Focused Procedure
- Load the datasets.
# PySpark example large_df = spark.read.parquet("/data/large_table") lookup_df = spark.read.parquet("/data/lookup_table") - Check the size of the lookup table.
lookup_size = lookup_df.rdd.mapPartitions(lambda p: [len(p)]).sum() print(f"Lookup size: {lookup_size / (1024 ** 2):.2f} MB")Confirm it is below the broadcast threshold (default 10 MB).
- Set a custom broadcast threshold if needed.
# Set to 100 MB for this job spark.conf.set("spark.sql.autoBroadcastJoinThreshold", 104857600)Use bytes; the default is 10 MB (10 000 000).
- Apply a broadcast hint explicitly (optional).
from pyspark.sql.functions import broadcast joined_df = large_df.join(broadcast(lookup_df), on="key", how="inner")Explicit hints override the automatic decision.
- Trigger an action to materialize the plan.
result = joined_df.count() print(f"Rows after join: {result}") - Inspect the physical plan.
joined_df.explain(extended=True)Look for
BroadcastHashJoinin the output. - Validate in the Spark UI.
- SQL tab: find the query ID.
- Stages tab: verify that the join stage has
BroadcastHashJoinand zero shuffle metrics. - Executors tab: ensure no
OutOfMemoryErrorand minimal disk spill.
Expected Checks
- Physical plan contains BroadcastHashJoin. If it shows
ShuffleHashJoin, the threshold was too low or the table was too large. - Shuffle metrics are zero. Check
Shuffle ReadandShuffle Writecounters. - Executor memory usage. Verify that the broadcast size plus existing cache fits within
executor-memoryminus overhead. UseExecutorstab orspark.executor.memorylogs. - Job completes without spills. Monitor
Disk Spillingcounters; heavy spills indicate the broadcast is too large.
Recovery & Fallback Strategies
- Broadcast fails due to size. Increase
spark.sql.autoBroadcastJoinThresholdor reduce the lookup DataFrame size (e.g., filter unnecessary columns). - Memory pressure. Reduce
--executor-memoryor add more executors to distribute the broadcast. - Skewed keys. Even with broadcast, a key that appears in millions of rows can overload executors. Consider
saltingor switching to asort‑merge joinif skew dominates. - Unsupported join type. If you need a full outer join, broadcast is not available. Accept the shuffle join or rewrite the logic.
Concrete Example
Assume you have a 5 MB lookup table and a 10 GB fact table. The following PySpark snippet demonstrates a broadcast join and verification steps.
# Load data
fact = spark.read.parquet("/data/fact")
lookup = spark.read.parquet("/data/lookup")
# Set threshold to 50 MB
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", 52428800)
# Join with hint
joined = fact.join(broadcast(lookup), on="id", how="inner")
# Trigger action
joined.count()
# Explain
joined.explain(extended=True)
After running, open the Spark UI, locate the query, and confirm the join stage shows BroadcastHashJoin and no shuffle metrics.
Limitations & Practical Checks
- Broadcast joins consume executor memory; if the broadcast size exceeds available memory, the job will fail with
OutOfMemoryErroror spill to disk. - Key skew can still cause load imbalance; broadcast does not mitigate skew.
- Broadcast is ignored for full outer joins or when the small DataFrame cannot be cached.
- Thresholds are applied per executor; inconsistent cluster configurations can lead to mixed behavior.
To check whether a broadcast join was used, run joined.explain(extended=True) and search for BroadcastHashJoin. In the Spark UI, the Stages tab will show zero shuffle metrics for that stage.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.