CONCEPT Cited by 1 source
Planner phase ordering¶
Definition¶
Planner phase ordering is the discipline of grouping query-planner rewrite rules into sequential phases, where each phase has its own active rewriter set and runs to a fixed point before the next phase starts. Some rewriters are gated — they only activate after a specific phase has completed. The phase order determines which rewrites fire first, and therefore which plan shape subsequent rewriters see.
Andres Taylor's canonical wiki framing (Source: sources/2026-04-21-planetscale-optimizing-aggregation-in-the-vitess-query-planner): "We have several phases that run sequentially. After completing a phase, we run the push-down rewriters, then move to the next phase, and so on."
Why phases exist¶
A flat rewriter soup — every rewrite rule eligible to fire at every iteration — has two problems:
- Rewriter interference. Two otherwise-correct rewrites can, in combination, produce a plan that neither would have produced alone. The canonical Vitess case: "push ordering under aggregation" + "split aggregation across a join" run in either order produce different final plans; the wrong order wedges
Orderingbetween the aggregator and the join, blocking aggregation pushdown entirely. - Premature commitment. Some decompositions (like splitting aggregation into local + global halves) expose new pushdown opportunities. If rewriters that consume the decomposed shape fire before the decomposition happens, they see the pre-decomposition tree and miss the opportunity.
Phases fix both by sequencing. Taylor: "By delaying the 'ordering under aggregation' rewriter until the 'split aggregation' phase, we can push down the aggregation under the join. This doesn't stop the 'ordering under aggregation' rewriter from doing its job, it just has to wait a bit before doing it" (Source: sources/2026-04-21-planetscale-optimizing-aggregation-in-the-vitess-query-planner).
Two roles for rewriters within a phase¶
Vitess's planner uses two rewriter roles, per Taylor:
- Transform rewriters — rewrite the tree to perform a specific task. "For example, the 'pull DISTINCT from UNION' rewriter extracts the DISTINCT part from UNION and uses a separate operator for it."
- Phase-gate rewriters — control when transform rewriters are enabled. "Some rewriters only turn on after reaching a certain phase." These don't modify the plan tree themselves; they flip an enablement flag.
The distinction turns the planner from "a set of rewrite rules" into "a control-flow graph whose nodes are rewriter invocations and whose edges are phase transitions."
The Vitess phase list (partial)¶
From the 2024-07-22 post, two phases are named explicitly:
- Initial phase — horizon expansion + straightforward pushdowns. Some rewriters are enabled; others are gated off.
- Split aggregation phase — aggregation gets decomposed into local + global halves (see concepts/local-global-aggregation-decomposition). The post implies the "ordering under aggregation" rewriter is now gated to start in this phase.
The post doesn't enumerate the full phase list. Taylor's framing ("several phases that run sequentially") implies more phases exist; vitessio/vitess #16278 contains the concrete enum.
Consequences for correctness and debugging¶
- Correctness is preserved regardless of phase ordering, because each rewrite is algebraically valid on its own. Phase ordering affects reachability of good plans, not validity of chosen plans.
- Debugging phase-ordering bugs is difficult because each rewriter looks correct in isolation. The incident at sources/2026-04-21-planetscale-optimizing-aggregation-in-the-vitess-query-planner presented as "OOM in VTGate" — not "rewriter X fires in wrong order" — and had to be traced back through the plan-tree evolution to the phase interaction.
- The fix is almost always cheap: move one rewriter to a different phase (see patterns/phase-gated-planner-rewriter). No new algorithm, no invasive restructuring.
Related architectures¶
Phase ordering is a classical compiler / query-optimiser technique:
- Compilers: pass ordering in LLVM / GCC — SSA construction must precede global-value-numbering; escape analysis must precede stack allocation; etc. Phase-ordering bugs are a known complex class in compiler engineering.
- Cost-based query planners (Volcano, Cascades, Calcite): organise rules into groups activated by strategy rather than explicit phases, but the same underlying discipline — some rewrites need to fire before others to be effective.
- Vitess's planner uses explicit phases over a fixed-point loop rather than Volcano/Cascades-style memo-based cost search. The trade-off: simpler reasoning, harder cost-based planning. For Vitess's cross-shard regime where the cost model is dominated by network hops, the explicit-phase approach is expressive enough.
Seen in¶
- sources/2026-04-21-planetscale-optimizing-aggregation-in-the-vitess-query-planner — canonical wiki introduction. Andres Taylor (PlanetScale / Vitess core, 2024-07-22) describes the planner's phase structure as load-bearing context for a bug fix: OOM in VTGate caused by "push ordering under aggregation" firing before "split aggregation," wedging
OrderingbetweenAggregatorandApplyJoin. Fix = delay the ordering rewriter to the split-aggregation phase. Shipped as vitessio/vitess #16278.
Related¶
- concepts/fixed-point-tree-rewriting — the convergence discipline each phase uses.
- concepts/vtgate-query-planner — the planner that uses phase ordering.
- concepts/push-aggregation-under-join — the rewrite protected by correct phase ordering in the 2024 incident.
- concepts/local-global-aggregation-decomposition — what the "split aggregation" phase performs.
- patterns/phase-gated-planner-rewriter — the pattern-level fix recipe.
- patterns/aggregation-pushdown-under-join — the protected pattern.
- systems/vitess