DAG-aware scheduling
Why can no number of machines beat the critical path, and how can adding machines slow a job?
Many jobs are DAGs (directed acyclic graphs): tasks with dependencies, where a task can start only after its predecessors finish. The makespan (total time from the first task start to the last finish) is bounded below by the critical path, which is the longest chain of dependent tasks. No number of machines can beat it.
The critical path is 9 minutes. With 2 machines or with 200 machines, the job cannot finish in under 9 minutes. C has 2 minutes of slack (it can start 2 minutes late without delaying D). Tasks A, B and D have zero slack: delaying any of them delays the whole job.
This is Amdahl's law (the serial part of a job limits the speedup, however many workers you add) restated as graph structure, the work-span bound of a query runtime applied to whole jobs. The serial fraction is literally a path through the dependency graph. So the useful priority key is not task size but remaining path length, with slack as its complement.
Two results are worth carrying:
- Graham's bound. Any greedy list schedule (never leave a machine idle if a task is ready) is within 2× of optimal. The sophistication ceiling is low, and critical-path ordering is close to free.
- Graham's anomaly. Under list scheduling, adding machines, shortening a task, or relaxing a dependency can lengthen the makespan. This non-monotonicity is real. It is not an implementation bug. It is why "we added nodes and it got slower" is sometimes literally true, not a measurement error.
The same mechanism appears at three scales: operator stages inside one query, tasks inside one job, and jobs inside a pipeline graph. Count it once: critical-path prioritization is scale-free.
Parallelism cannot beat the longest path. Schedule by remaining path, not by task size.