Now one full diagnosis. All numbers here are made up for teaching. They are not measurements.
Imagine the shop has 1 billion paid orders and 2 million customers. To keep the numbers simple, we count only paid orders. A daily job joins them and adds up the total by country.
The job takes 4 hours, which is 240 minutes. Step 1, Jobs tab: Job 5, the write, takes 230 of the 240 minutes.
Step 2, Stages tab: Stage 12 takes 212 minutes and has 200 tasks.
Step 3, open the 200 tasks of Stage 12. The Summary Metrics table shows this.
| Metric | Min | 25th | Median | 75th | Max |
|---|
| Duration | 30 s | 40 s | 45 s | 55 s | 3 h 30 min |
| Shuffle Read Size / Records | 300 MB / 3 M | 400 MB / 4 M | 450 MB / 4.5 M | 500 MB / 5 M | 10 GB / 100 M |
| Spill (Memory) | 0 | 0 | 0 | 0 | 40 GB |
| Spill (Disk) | 0 | 0 | 0 | 0 | 9 GB |
The longest task takes 210 minutes. The median task takes 45 seconds. That is 280 times longer.
The longest task also read 100 million rows, which is one tenth of all 1 billion paid rows. Sort the task list by Spill: it is the only task that spills. This is skew, and the spill is a result of it.
Now find the cause and the fix.
- Step 4, SQL tab: the join is a SortMergeJoin (both sides are shuffled and sorted by the key). Both sides have an Exchange. Customers is 80 MB.
- Step 5, Executors tab: GC time is small and no tasks failed. Memory is not the main cause.
- Steps 6 and 7, Storage and Environment tabs: nothing is cached, and spark.sql.adaptive.enabled is false. The broadcast limit is not listed, so it is the default 10 MB.
- Last, a count by customer_id: one business account, customer 7, has 100 million orders.
The cause is the hot key, customer 7. A sort-merge join sends all of its rows to one task.
The customers table is 80 MB, over the 10 MB broadcast limit. So Spark picked a sort-merge join, as its rules say. AQE checks the real size, so it also would not broadcast 80 MB.
But AQE would split the hot partition. It is on by default since Spark 3.2, so someone turned it off here. You have two fixes: turn AQE back on, or broadcast customers on purpose.