Repository navigation
Joint planning search: search independent components separately (method 5) - #797
Merged
Merged
Conversation
zzylol
force-pushed
the
feat/joint-search-2-components
branch
2 times, most recently
from
October 21, 2026 05:58
48d49d8 to
ac26fcf
Compare
zzylol
force-pushed
the
feat/joint-search-2-components
branch
from
October 21, 2026 07:14
ac26fcf to
f10d719
Compare
…-planning-search method 5) Queries that read disjoint sources share no Pass 2 rewrite, raw-data retention or node charge. Under cost model 1 (a sum of node charges, no measured-table calibration) each such component is searched on its own and the selections are combined into one whole-workload candidate, which Stage 3 checks and prices again. The combination is used only when it is the joint search's selection: - it is one of the joint search's Stage 1 candidates (the Pass 2 rules do not combine every rewrite, and cap candidates per workload); - no other combination ties with it within Stage 3's tolerance: each component's runner-up costs more than its selection by 4e-9 of the workload's price (candidates within 1e-12 rounding cost the same, and the first in enumeration order wins, as in the joint order); - its price is the sum of the components'. Otherwise the workload is searched as one, and the selection report says why (SearchedAsOne). Cost models 2 and 3 (peak cores, cluster limits) and calibrated cost tables are searched as one. Stage 2 gains optimize_physical_asap_assigned and PhysicalCandidate::assignment to rebuild the combined materialization.
zzylol
force-pushed
the
feat/joint-search-2-components
branch
from
October 21, 2026 08:16
f10d719 to
5710f34
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
After #792, the default search still composes every valid whole-workload choice. A 9-query PromQL workload from ASAPQuery's random mixed set (seed-862 workload-01) takes 128 s, because its 7 queries over
dataand its 2 overdata_totalmultiply each other's alternatives, even though no rewrite can link them.This PR implements method 5 of
docs/design_docs/proposals/joint-planning-search.md, "Split independent components".Part of #673.
What
Components. Queries are grouped by the sources they read: two queries are in one component when they read a common source, directly or through other queries. The source is keyed by name, because data facts are keyed by name.
Search per component. Under cost model 1, each component is searched on its own with Joint planning search: stream Stage 1 to Stage 3 and reject permanently invalid query candidates (methods 2 + incumbent) #792's search. The selections are then combined into one whole-workload candidate, which Stage 3 checks and prices again.
Exactness preconditions. The combination is used only when all of these hold:
Otherwise the workload is searched as one, and the report says why.
Selection report.
SearchReportgains:components: queries, candidates checked and selected id for each component;searched_as_one: the reason the workload was searched as one;runner_up_cost_per_second: the selection's margin.The combined candidate's id joins the components' ids, e.g.
P505-m80+P4-m8.How
components::source_componentsruns union-find over theScansources each root reaches.components::search_componentsrunsrun_stage1_to_stage3_from_pass1on each component's own Pass 1 inventory. It maps each component's selected Pass 1 choice onto the joint inventory's targets (by aggregate node and measure), then finds the matching joint Stage 1 candidate withstage1_candidates_of_choice.optimize_physical_asap_assignedrebuilds the materialization one summary build at a time. Each build takes the option its component chose for it, in discovery order. Components are disjoint, so their relative discovery order is the same in the joint DAG.PlanSelectortracks the cheapest valid price and the cheapest price more than rounding above it. That runner-up is what the tie check reads.Stage1ToStage3Rungainsstage1_selected, the logical candidate the selection implements, so a component run hands its choice and roots to the combination.Key code interfaces added / modified
crates/plan-selection/src/lib.rscrates/plan-selection/src/pass/stage1_to_stage3.rscrates/physical-asap-optimization/src/lib.rscrates/logical-asap-optimization/src/workload_candidates.rs: unchanged in this PR.stage1_candidates_of_choicefrom #792 is the membership check.Usage
The user plans the 9 PromQL queries of seed-862 workload-01 with
plan_installableunder cost model 1 (Fargate prices):(The numbers come from running the local converter against this commit. The converter isn't part of this PR.)
Before this PR
With #792, the 9-query PromQL prefix of seed-862 workload-01 takes 128 s at 217 MB, and checks 131,088 candidates.
After this PR
Release build of the same converter,
plan_installableend to end, PromQL queries only:The 9-query plan is byte-identical, as installable plan JSON apart from the selection report, to the joint search's plan from #792. The 3-, 5- and 6-query prefixes are single-component and unchanged.
All 30 ASAPQuery workloads (seed-862, seed-862-x5, seed-862-long), PromQL only: see the comment below once measured.
The 7-query
datacomponent dominates: 8,208 candidates in about 10 s. Later PRs (methods 1, 6, 7, then 3 and 4) target it.Verification
cargo test --workspace --locked: passes.joint_search_equivalence.rs. Each check compares the default search withStage1ToStage3Search::exhaustive(). Existing tests keep passing; the random query generator now takes the gauges to draw from. New tests:random_workloads_over_disjoint_sources_combine_their_components: 40 seeded random workloads over two gauges and a counter under cost model 1. They select the exhaustive plan, and at least 10 are actually combined (componentsnon-empty).components_follow_shared_sources: a query overmandnlinks themandnqueries into one component, and thec_totalquery is its own./usr/bin/timearound the converter. Plans were compared as JSON with the Joint planning search: stream Stage 1 to Stage 3 and reject permanently invalid query candidates (methods 2 + incumbent) #792 joint search.Limitations and follow-up
calibration_fiterrors. It can fail, with a Stage 3 cost error, on a candidate that a pruned search would never offer. This matches the exhaustive search, which prices that candidate too.