Repository navigation
fix(plan-selection): certify lower bounds for query-time scans, windows and builds - #987
Merged
Merged
Conversation
zzylol
force-pushed
the
fix/query-time-lower-bounds
branch
from
October 28, 2026 03:23
1b5a4bd to
871f33d
Compare
zzylol
marked this pull request as ready for review
October 28, 2026 03:23
…ve certified bounds Fails on main: a query-time scan, its time range and the build over it all have lower bound 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ws and builds A query-time scan was never certified: lower_bounds priced it with no lookback, so price_node fell back to rows_held or failed, and every node above it stayed at 0. The bound now uses the shortest window any possible reader reads (time range, pane chain, through time shifts): the scan reads its readers' longest window, or every held row, both at least that. Query-time Scan, TimeRange, TimeShift, Aggregate, SummaryAgg and PaneChain are priced at the slowest query rate over those rows, so the MILP no longer ranks repeated query-time scans as free. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… their template size Stage 3 only resizes a sketch to larger parameters, and the analytical shape never charges a larger sketch less, so a build priced at its template's parameters is a lower bound on every size it can take. KLL and the other resizable sketches, at ingestion and at query time, are certified this way, except when the measured table has entries for that family: interpolated measurements need not grow with size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d below the evaluated cost Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ss 2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; DDSketch builds keep the raw-domain guard A measured cost table interpolates by sketch size and need not rise with it, so a family with any measured entry (any operator, either phase) gets no size-based bound, and neither do the estimates and merges above its builds. A query-time DDSketch build, like a DDSketch pane chain, is priced only from producers that agree on the raw non-negative domain. The search's soundness check allows a relative rounding step, since the bound and the evaluator sum the same prices in different orders. Renames lookbacks to shortest_reader_window_ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zzylol
force-pushed
the
fix/query-time-lower-bounds
branch
from
October 28, 2026 04:11
de0a1fe to
6eb1e5b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The joint search orders its proposals by the MILP's lower bound, the sum of each selected candidate's
local_cost. Query-time scans, windows and builds hadlocal_cost0, so a plan that rescans 5 minutes of raw rows every evaluation looked free next to an ingestion path that has a positive bound. In example C (#963) the q1 query-time path has true cost 0.1560/s and bound 0, while the ingestion path costs 0.0524/s and has bound 0.0039. The search proposed every zero-bound combination first.What
costing/lower_bounds.rsnow certifies bounds for:Scan,TimeRange,TimeShift,Aggregate,SummaryAggandPaneChain(NotMaterializedorMatAtQuery; never under a chain kept across evaluations, as before);PaneChains of every sketch family, not only DDSketch (KLL, CMS, Count Sketch, KMV, HLL, UnivMon).Cause of the 0:
certified_pricecalledprice_nodewith no lookback. A query-time scan's rows are "the arriving rows of the longest window read above it", so with no windowprice_nodefell back torows_heldor failed, and every node above the scan stayed uncertified.How the bound stays sound:
shortest_reader_windowsgives each candidate the least window any candidate that may read it reads, counted as the evaluator'swindows_readcounts windows (a time range's range, a pane chain's panes, through time shifts). The evaluator reads the selected readers' longest window, or every held row when none has one. Both read at leastrows(shortest window)capped byrows_held, the quantity priced here.query_rate_floor), as for the existing query-reader bounds.with_failure_probabilitytakes the maximum with the current size for every family, HLL'smin_precisionstarts at the current precision), and the analytical shape (sketch_shape) never charges a larger sketch less, so the template's price is at most its price in any plan. A measured operation-cost table interpolates between measured sizes and need not grow with size, so a resizable sketch family with any measured entry (any operator, either phase) is not certified (template_price_is_a_floor,measured_family). This also covers the estimates and merges above its builds, which a measuredSummaryEstimateorSummaryMergeentry prices by interpolated size: they are certified only over a certified build. A query-time DDSketch build, like a DDSketch pane chain, is priced only from producers that agree on the raw non-negative domain, which decides whether it keeps one bucket store or two.offset): Stage 3 scans the width of the union of the readers' windows (PhysicalASAPDAG::scan_window) and keeps raw rows up tooffset + widthat its own charge; the bound prices the shortest reader width and no retention, so it stays below. The bounds are not offset-aware otherwise.UsageOverTime, as before.search.rs: "actual cost … is below certified local bound"). No suite run below triggered it.Key code interfaces added / modified
lower_bounds::shortest_reader_windows(&CandidateConfigurationInventory) -> Vec<Option<u64>>(new, private).certified_pricetakes the readers' shortest windows (private).lower_bounds::template_price_is_a_floor(&ASAPOp, &CandidatePlanningContext) -> bool(new, private): whether a summary build's template price bounds every size Stage 3 can give it.lower_bounds::measured_family(&SketchParams, &MeasuredOperationCosts) -> bool(new, private): whether the measured table has any entry for the sketch's algorithm.Major algorithm changes
The query-time whitelist of
lower_bounds::applynow includes scans, windows, shifts, aggregates and summary builds; the ingestion whitelist includes pane chains of every sketch family whose template price is a floor.Before this PR / After this PR
Example C on main (
SELECT city, p90 … GROUP BY citywithSELECT p90 … WHERE city = 'NYC' OR city = 'SF', 5-minute window, every 10 s), seed round, instrumented:The remaining 8 proposals before the optimum are rejections (q0 reading a grouped KLL fails its accuracy target), which #964 targets.
Per-city p90 pair (
city = 'NYC'andcity = 'SF'): on the old main 0.2084510/s against 0.1048378/s separate. This PR alone gives 0.1048378/s. Since #973 merged, main gives it too.Regression tests, branch against main (both on
f06a5556, same machine, run alternately)sharing_issue_regressions(incl. #923exact_coarse_sum_reuses_fine_sum)memo_covers_whole_workload_pass2::topk_reusememo_covers_whole_workload_pass2::shared_sizesfiner_aggregate_reuse)The earlier version of this PR certified only query-time nodes and made #923 fail 3 of 3: the structural baseline weighed the query-time scan at its certified price while the competing KLL pane chains stayed at 0. Certifying the pane chains at their template size restores the comparison.
Not done
shared_sizesstill misses the whole-workload plan (one query-time KLL k=345 read by both estimates).Verification
Remote, clnode143, on the branch rebased on
f06a5556(#988):query_time_scans_and_builds_have_certified_boundsfails on main'slower_bounds.rs(scan bound 0). It now also coverssum_over_time(latency[5m] offset 1m): positive bounds, at most the evaluated cost underscan_windowpricing.a_kll_build_bound_holds_for_every_resized_size(the KLL bound stays below the evaluated cost at failure probabilities 0.01, 0.001 and 0.0001, which resize it larger),a_measured_kll_build_is_not_certified,a_measured_kll_estimate_keeps_the_bound_below_the_cost(an independent review's counterexample: measuredSummaryEstimateentriesKll{k:8}at 5e9 ns andKll{k:20000}at 1 ns gave bound 413.51 above the evaluated 407.63 before the fix).cargo test -p asap-plan-selection --lib: 377 passed, 1 failed:producer_reuse_rules_produce_validated_shared_plans, which fails the same way on mainf06a5556.independent_plan_seed3,joint_search_equivalence14,production_rollup_workloads4,identical_exact_queries2,rollup_controlled2,memo_covers_whole_workload_pass27 passed and 1 ignored,finer_aggregate_reuse10,sharing_issue_regressions12 (5 runs).cargo fmt --all --check; clippy-D warningsonasap-plan-selectionand the integration tests: clean.d4152bce); the instrumentation is not committed.Refs #963
🤖 Generated with Claude Code