Inter-operator (vertical / pipeline) parallelism
- Distinct operators run at the same time even though data flows between them: a downstream operator does not wait for its child to finish all output before starting (
29:57).
- Also called pipeline parallelism; exchange operators are still needed to coalesce shards and produce the right number of output streams (
30:24).
Worked example
- Worker 1 runs the join over the two tables and emits joined tuples as a stream (
30:24).
- Instead of fusing the projection into that pipeline, it runs on its own worker — justified when the projection is CPU-intensive (e.g. "a hash of a hash of a hash"), so the join worker is not burdened by it (
30:59).
- The join worker pushes output into a queue; the projection worker waits on that queue, crunching each item as it arrives (
31:26).
flowchart LR
W1[Worker 1: Join] -->|queue of tuples| W2[Worker 2: expensive projection] --> OUT[Output]
Where it matters
- Most common in streaming systems — Spark SQL, Kafka — where the input has no end: stock ticks, temperature readings. Unlike a finite table scan that terminates, the operator is always running (
31:26, 31:48).
Bushy parallelism
- Simply the combination of horizontal (intra-operator) and vertical (inter-operator) parallelism used at the same time; exchange operators are still required to confirm completeness from the sub-plans below (
32:03).
- Contrived example — a cartesian product across
A, B, C, D (32:28):
- Join
A ⋈ B and join C ⋈ D run simultaneously.
- Workers 3 and 4 run the cross join above, buffering what they have seen and matching new tuples as they arrive.
- Acknowledged as very expensive with exploding result size — but the computation still runs in parallel instead of queueing everything up serially.
flowchart BT
A[Scan A] --> J1[Join A-B<br/>worker 1]
B[Scan B] --> J1
C[Scan C] --> J2[Join C-D<br/>worker 2]
D[Scan D] --> J2
J1 --> X[Cross join<br/>workers 3 and 4]
J2 --> X