Class CostEstimator

java.lang.Object
com.darkcollective.relix.cost.CostEstimator

public final class CostEstimator extends Object
Estimates the relative I/O cost of a RelNode expression by inspecting the types of its leaf relation symbols.

Cost is represented as a CostTier ordinal — higher ordinal means more expensive. The cost of a composite expression is the maximum (worst-case) cost of any leaf in its sub-tree, on the principle that the most expensive source dominates overall I/O cost.

Leaf cost mapping

A null symbol table is permitted; in that case every RelationNode leaf resolves to CostTier.FILE (conservative fallback).

Recursion into QueryRelationSymbol bodies is bounded by an internal depth limit (32) to guard against unexpectedly deep view chains; beyond that limit CostTier.FILE is returned.

Cardinality estimation

In addition to the coarse tier, estimateRows(RelNode) produces a numeric row-count estimate when the leaf relations carry RelationStatistics (supplied via a StatisticsSource). Row counts are propagated through operators with simple, documented heuristics (selection selectivity, join cardinality, etc.). When per-column distinct counts are available, three estimates are sharpened for the common case where the relevant input is a base relation: a grouped aggregation uses the product of its grouping columns' distinct counts (capped at the input size), an inner equi-join uses |L|·|R| / max(distinct(L.k), distinct(R.k)) (with a composite key's distinct count taken as the product of its columns'), and a selection reads its own predicate rather than assuming DEFAULT_SELECTIVITY — 1/d for an equality, n/d for an IN list, nullCount/rowCount for IS NULL, combined through the connectives under the independence assumption. All three fall back to their coarse heuristic when the columns or statistics are unknown. The estimate is honest: it is OptionalLong.empty() whenever a contributing leaf has no known row count, so callers can fall back to the tier model rather than act on a fabricated number.

This class is stateless beyond its injected SymbolTable and StatisticsSource; a single instance may be reused across multiple estimate(RelNode) / estimateRows(RelNode) calls.

  • Constructor Details

    • CostEstimator

      public CostEstimator(SymbolTable symbolTable)
      Creates a CostEstimator backed by the given symbol table with no statistics (tier-based estimation only).
      Parameters:
      symbolTable - the symbol table used to look up leaf relation names; may be null, in which case all leaf names resolve to CostTier.FILE
    • CostEstimator

      public CostEstimator(SymbolTable symbolTable, StatisticsSource statistics)
      Creates a CostEstimator backed by the given symbol table and statistics source.
      Parameters:
      symbolTable - the symbol table used to look up leaf relation names; may be null (all leaves then resolve to CostTier.FILE and carry no row count)
      statistics - the source of per-relation statistics; must not be null (use StatisticsSource.NONE for none)
  • Method Details

    • withObserved

      public CostEstimator withObserved(ObservedCardinalities observed)
      Lets this estimator prefer a row count a previous run actually produced over the one it would compute.

      A measured count beats an estimate wherever there is one, which is why it is consulted before the walk rather than blended into it: a selectivity guess applied on top of a real number would make the answer worse than either input.

      Parameters:
      observed - the recorded counts; must not be null (ObservedCardinalities.NONE for none)
      Returns:
      this estimator, for chaining
    • estimate

      public CostTier estimate(RelNode node)
      Returns the cost tier for the given expression tree.
      Parameters:
      node - the expression to estimate; must not be null
      Returns:
      the cost tier; never null
    • estimateRows

      public OptionalLong estimateRows(RelNode node)
      Estimates the number of rows the given expression produces.

      Returns OptionalLong.empty() when the estimate cannot be made because some contributing leaf relation has no known row count. A present value is a heuristic upper-bound-flavoured estimate, suitable for comparing the relative size of two sub-trees (e.g. to pick a hash-join build side).

      Parameters:
      node - the expression to estimate; must not be null
      Returns:
      the estimated row count, or empty if unknown