Class QueryOptimizer
The optimizer takes a SemanticModel produced by semantic analysis
and rewrites each query's RelNode tree to a semantically equivalent
but more efficient form. Every transformation is logged in an
OptimizationContext and returned as an OptimizationResult
so the audit trail can be rendered by the console's optimization report.
Optimization phases
The rules, their order, and which groups are iterated are declared by
OptimizationPipeline, which this class builds once per query and runs.
The six phases run once each, in order, and the rules within a phase are
swept repeatedly until they stop making progress (capped at
OptimizationPipeline.DEFAULT_MAX_ITERATIONS sweeps):
- simplify — expression then predicate simplification.
- pushdown — selection splitting, the nest/unnest laws, selection pushdown, partition/group pruning, and the join rules.
- cleanup — selection merging, the projection rules, and the redundant-γ/δ/τ eliminations.
- sip — folding a constraint into
CLOSURE/TRACE/FIX/a generator. - limit — limit pushdown and the top-N fusion.
- prune — column pruning, once.
The split into phases is load-bearing, not cosmetic: SEL-003/
PROJ-003 and SEL-001/SEL-002 are mutual inverses, so iterating all
the rules together would never terminate. See OptimizationPipeline for the
placement rule a new pass has to satisfy.
Three rewrites run outside the pipeline, in optimize(SemanticModel)'s
per-query preamble, because each needs the model's SymbolTable and every rule
in the pipeline is a pure syntactic rewrite: ViewInliner
(INLINE-001) expands view references, RenameEliminationPass
(RENAME-001..RENAME-004) removes the alias wrappers inlining leaves
behind and tidies the column renames, and LateralDecorrelationPass (LATERAL-001) turns an uncorrelated
LATERAL into a × — which needs the table to resolve the function and
classify its body as deterministic. All three run before schemas are re-inferred for the
expanded tree.
Rule by rule, in the order they run:
- Expression simplification — bottom-up constant folding, arithmetic
identity elimination, constant accumulation, and idempotent function
call elimination (
EXPR-001..008). - Predicate simplification — constant-branch folding and double-NOT
elimination (
PRED-001..002). - Selection splitting — conjunctive predicates decomposed into stacked
selections (
SEL-001) to expose independent pushdown opportunities (SelectionSplitPass). - Nest/unnest round-trip laws — collapse a
μover aCOLLECTto a projection and push σ/π belowμ(NEST-001..003) (NestUnnestPass). - Selection pushdown (
SEL-003..009) (SelectionPushdownPass). The projection rules, including the inversePROJ-003, are in the cleanup phase below. - Partition pruning into
WINDOW/TopK— push a partition-key equality below the operator so only the matching partition is computed (WINDOW-001,TOPK-001) (SelectionIntoWindowPass). - Group pruning into
OPTIMIZE— push aPERgrouping-key equality below the operator so the solver runs for only the matching group (OPTIMIZE-001) (SelectionIntoOptimizePass). - Cross-product to theta-join conversion (
JOIN-001). - Selection into join inputs (
JOIN-002,SEL-005). - Selection and projection merging — cleanup pass
(
SEL-002,PROJ-001..002). - Redundant-grouping elimination — collapse a γ stacked redundantly on
another γ (
AGG-001) (RedundantGroupingPass). - Redundant-DISTINCT elimination — remove a δ whose input is already
duplicate-free (
DIST-001) (DistinctEliminationPass). - Redundant-SORT elimination — remove a τ whose input already delivers a
satisfying order (
SORT-001) (SortEliminationPass). - Selection-into-CLOSURE pushdown — fold a constant endpoint equality above
a
CLOSUREinto a source/target bound, collapsing all-pairs reachability to single-source/single-pair (CLOSURE-001) (SelectionIntoClosurePass). - Selection-into-TRACE pushdown — fold a constant endpoint equality above a
TRACEinto a source/target bound, collapsing all-pairs optimal-path search to single-source/single-pair (TRACE-001) (SelectionIntoTracePass). - Magic-sets into
FIX— push a selection over frozen columns into aFIXleast-fixpoint so the recursion is seeded and restricted by the bound rather than computed in full (FIX-001) — the general case of which CLOSURE/TRACE pushdown are fixed-shape instances (SelectionIntoFixpointPass). - Bound pushdown into a monotone generator — fold an upper bound above an
unbounded ascending generator into a production stop, so the scan
terminates (
GEN-001) (SelectionIntoGeneratorPass). - Limit pushdown (
LIM-001..004). - Column pruning — a top-down "required columns" walk that narrows every
base relation to the columns the query actually reads (
PROJ-004) (ColumnPruningPass). Runs last so it cannot hide the shapes the pattern-matching phases above match on.
This class is stateless and safe to reuse across multiple optimization runs.
-
Constructor Summary
ConstructorsConstructorDescriptionConstructs aQueryOptimizerwith the default full rule set. -
Method Summary
Modifier and TypeMethodDescriptionoptimize(RelNode node, String queryName, SchemaAnnotations schemas, OptimizationContext ctx) Optimizes a singleRelNodetree, recording all transformations in the supplied context.optimize(SemanticModel model) Optimizes all root queries in the givenSemanticModel.optimize(SemanticModel model, QueryEventListener listener) Optimizes all root queries inmodel, emitting aQueryEventtolistenerfor every rule that fires (in addition to recording it in the returned results).optimize(SemanticModel model, QueryEventListener listener, DistinctnessSource distinctness) Asoptimize(SemanticModel, QueryEventListener), plus a per-leafDistinctnessSourcesoDIST-001removesδover an inherently-distinct leaf (e.g.optimize(SemanticModel model, QueryEventListener listener, DistinctnessSource distinctness, MonotoneGeneratorSource monotoneGenerators) Asoptimize(SemanticModel, QueryEventListener, DistinctnessSource), plus a per-leafMonotoneGeneratorSourcesoGEN-001folds an upper-boundσover a monotone unbounded generator into a production stop.
-
Constructor Details
-
QueryOptimizer
public QueryOptimizer()Constructs aQueryOptimizerwith the default full rule set.
-
-
Method Details
-
optimize
public RelNode optimize(RelNode node, String queryName, SchemaAnnotations schemas, OptimizationContext ctx) Optimizes a singleRelNodetree, recording all transformations in the supplied context.Every rule the optimizer ships is a pure syntactic rewrite, so this needs neither a symbol table nor a cost model. Cost-driven join decisions are the planner's, where they can be made without permuting the logical schema.
The rules that ask what a function may do — whether a call folds, or an aggregate ignores multiplicity — read the
FunctionCatalogoffctx.optimize(SemanticModel)puts the model's own catalogue there; a caller entering here directly supplies one when it wants those rules to fire, and gets a slower plan rather than a wrong one when it does not.- Parameters:
node- the root of the query tree to optimize; must not be nullqueryName- display name used in transformation records; must not be blankschemas- schema annotations from semantic analysis; must not be nullctx- context that accumulates transformation records; must not be null- Returns:
- the optimized tree; the original
nodewhen no rules fired
-
optimize
Optimizes all root queries in the givenSemanticModel.Each root query statement is optimized in the order it appears in
SemanticModel.rootQueries(). For aNamedQueryTargetthe symbol is looked up in the model's symbol table:- If the symbol is a
QueryRelationSymbol(a named view), itsQueryRelationSymbol.body()is optimized using all phases and the result is captured in anOptimizationResult. - If the symbol is not found or is not a
QueryRelationSymbol(e.g. a source table), a trivial pass-through result is returned with aRelationNodeleaf as both original and optimized.
For an
ExpressionQueryTarget(an inlinequery { … }statement) the expression is optimized directly and assigned the generated name"query[n]"wherenis the 1-based ordinal of inline queries encountered so far.Schema annotations carried in
SemanticModel.nodeSchemas()are forwarded to each optimization pass so that schema-dependent rules (e.g. PROJ-001) can operate correctly.- Parameters:
model- the semantic model to optimize; must not be null- Returns:
- unmodifiable list of per-query results, in root-query order; never null; empty when the model has no root queries
- If the symbol is a
-
optimize
Optimizes all root queries inmodel, emitting aQueryEventtolistenerfor every rule that fires (in addition to recording it in the returned results).- Parameters:
model- the semantic model to optimize; must not be nulllistener- notified on each rule firing; must not be null (useQueryEventListener.NONEfor no observation)- Returns:
- unmodifiable list of per-query results, in root-query order
-
optimize
public List<OptimizationResult> optimize(SemanticModel model, QueryEventListener listener, DistinctnessSource distinctness) Asoptimize(SemanticModel, QueryEventListener), plus a per-leafDistinctnessSourcesoDIST-001removesδover an inherently-distinct leaf (e.g. a duplicate-free generator). The CLI supplies a generator-backed source;DistinctnessSource.NONEdisables the leaf rule.- Parameters:
model- the semantic model to optimize; must not be nulllistener- notified on each rule firing; must not be nulldistinctness- the per-leaf duplicate-free lookup; must not be null- Returns:
- unmodifiable list of per-query results, in root-query order
-
optimize
public List<OptimizationResult> optimize(SemanticModel model, QueryEventListener listener, DistinctnessSource distinctness, MonotoneGeneratorSource monotoneGenerators) Asoptimize(SemanticModel, QueryEventListener, DistinctnessSource), plus a per-leafMonotoneGeneratorSourcesoGEN-001folds an upper-boundσover a monotone unbounded generator into a production stop. The runtime supplies a generator-backed source;MonotoneGeneratorSource.NONEdisables the rule.- Parameters:
model- the semantic model to optimize; must not be nulllistener- notified on each rule firing; must not be nulldistinctness- the per-leaf duplicate-free lookup; must not be nullmonotoneGenerators- the per-leaf ascending-generator lookup; must not be null- Returns:
- unmodifiable list of per-query results, in root-query order
-