Skip to content

Search: certify lower bounds for query-time scans and builds #963

Open

Description

@zzylol

Problem, by example

Same workload as #964: q0 = p90 per city, q1 = p90 over city IN ('NYC','SF'). Both run every 10 s over 5 minutes of metrics (666.67 rows/s, 48 B rows), ε = 0.01, WholeResult. Numbers are from an instrumented run on main (d4152bce).

q1 has two plans that differ in two candidates:

q1 plan Lower bound (Σ local_cost) True cost
Query-time scan, then a KLL built at query time 0 0.1560114/s (scan 0.1160006: 20000 rows/s × 48 B × 1e-7 plus CPU)
Ingestion scan, then an ingestion KLL pane chain 0.0038686 0.0524189/s

The bound ranks the expensive plan first. In the seed round on main, the MILP proposes all 13 zero-bound combinations (5 priced at about 0.332, 8 rejected) before it reaches the ingestion path at evaluation 14–15. On the #952 branch the same ordering left about 150 zero-bound combinations, more than the 5 s seed round could evaluate, so the search returned 0.3320576/s instead of 0.2284651/s.

Why it happens

costing/lower_bounds.rs assigns a certified local cost only to:

  • ingestion Scan, Project and TimeRange;
  • exact or DDSketch ingestion PaneChains;
  • query-time Project, SummaryEstimate and SummaryMerge.

Every other node gets 0 ("Unsupported pricing contexts contribute zero"):

  • query-time Scan, TimeRange and Aggregate;
  • query-time KLL SummaryAgg and PaneChain builds;
  • Filter.

round_down_small_bounds also zeroes bounds smaller than MINIMUM_RELATIVE_COEFFICIENT of the largest one, which removes most KLL ingestion pane chains.

A query-time scan's cost does not depend on its readers: every evaluation of a query that reads it scans its window. A bound of query_rate_floor × rows_in_window × (cpu + bytes) is certifiable, the same way the ingestion scan's bound is.

A quick prototype that allowed query-time Scan in lower_bounds.rs still produced 0, because certified_price returned no price for it. Why was not investigated.

Proposal

  • Certify lower bounds for query-time Scan and TimeRange: rows in the window × the minimum query rate × the unit prices. Do the same for query-time Aggregate and summary builds: their per-row CPU over the same rows.
  • Find out why certified_price returns none for query-time nodes.
  • Revisit the round-down threshold when bounds of very different sizes coexist.

Scope and acceptance

  • In scope: lower bounds for query-time Scan, TimeRange, Aggregate, SummaryAgg and PaneChain builds.
  • Acceptance:
    • in the example, the query-time q1 path's lower bound is at least 0.116/s;
    • the seed round on main reaches the 0.2284651 plan within at most 3 evaluations;
    • every lower bound stays at or below the evaluated cost on the existing suites. Add a check that asserts this for every priced proposal.

Related

Activity

  1. added
    enhancementNew feature or request
    cost-modelCost formulas, statistics, ranking, and selection
    optimizerWorkload optimization and plan selection
    searchCandidate-plan search space and algorithms
    on Oct 27, 2026
  2. zzylol commented on Oct 27, 2026

    @zzylol
    ContributorAuthor

    Another workload where the memo search misses a plan it holds. The cause matches this issue: the cheaper plan's query-time KLL build has lower bound 0. Found by the differential test in PR #975 (shared_sizes in memo_covers_whole_workload_pass2.rs).

    Workload: quantile_over_time(0.95, m[5m]) at ε = 0.01 and quantile_over_time(0.5, m[5m]) at ε = 0.05, both with δ = 0.001 and evaluated every minute, over 1,000,000 series sampled every 15 s.

    Cheapest plan (whole-workload path): 2.4145834/s. One query-time KLL with k = 345 and failure probability 0.001 over the shared 5-minute window, read by both estimates.

    The memo holds that plan. SummaryStates::derive rewrites the q=0.5 reader from KLL k = 66 to Kll { k: 345, fp: 0.001 }, and the q=0.95 reader is already at k = 345. The search still does not select it:

    Memo budget Evaluations Result
    default (120 s, 128 evaluations) 16; pane widths still pending; lower bound none 3.2787667/s on one machine, 3.3738667/s (the plain exact plan) on another
    300 s, 4096 evaluations 19 of 4096; the complete catalog of 2557 supplier sets is reached; lower bound 0, gap 1.0 3.2787667/s, still the seed round's plan
    exhaustive, 300 s — no validated plan

    Why this belongs here rather than in a separate issue:

    • Every query-time KLL plan has lower bound 0, so the MILP has no ordering among them. On the complete catalog, each solve takes about 15 s, so 300 s buys only 19 proposals.
    • The pane-width rounds also take most of the default budget. But even once the full catalog is available, the missing bound is what keeps the search from reaching the k = 345 plan.

    Acceptance for this issue: shared_sizes in memo_covers_whole_workload_pass2.rs passes and its #[ignore] is removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    cost-modelCost formulas, statistics, ranking, and selectionenhancementNew feature or requestoptimizerWorkload optimization and plan selectionsearchCandidate-plan search space and algorithms

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions