Environment
- Tool:
control_plane --example inspect_physical_dag (normal BackendLocalPlanningSnapshot::compile path)
- Snapshots: version 1, derived from
docs/examples/asapquery-compatibility-demo-snapshot.json;
source_sample_interval_ms = 1000, horizon_seconds = 3600, no window_candidates supplied.
Instant queries use lookback 1s. sum/count/avg queries use implicit_exact; w14 uses
EpsilonDelta { epsilon: 0.01, delta: 0.01 } because it contains a quantile.
Related: #701 (same snapshot setup).
Workloads and results
Metric data, scraped every 1s.
| id |
query |
repeats every |
result |
| w3 (#701) |
quantile by (job) (0.9, data) |
1s |
compiles: DDSketch grouped by job, tumbling 1s/1s, pane 1s |
| w12 |
sum by (job) (data) |
1s |
compile error |
| — |
sum(data) |
1s |
compile error (same as w12) |
| w13 |
avg_over_time(data[5m]) |
30s |
no state; QueryPlan is a single exact_fallback |
| w14 |
avg_over_time(data[5m]) / quantile_over_time(0.5, data[5m]) |
30s |
no state; single exact_fallback |
| w15 |
count by (job) (data) |
1s |
no state; single exact_fallback |
| — |
count(data) |
1s |
no state; single exact_fallback |
| w16 |
avg by (job) (data) |
1s |
no state; single exact_fallback |
| — |
sum by (job) (sum_over_time(data[5m])) |
30s |
compiles: Sum state, read_materialization → exact_readout → sum by (job) |
1. Instant sum fails to compile
Error: Query { query_id: "compat-query-0", reason: "instantaneous sample selection is not a temporal accumulator readout" }
Both sum by (job) (data) and sum(data) fail. The same instant-selector shape is handled three
different ways: quantile by (job) (φ, data) is materialized, count by (job) (data) falls back to
exact, and sum by (job) (data) is a hard compile error. Expected either a supported plan or exact
routing, consistently across aggregations.
2. avg_over_time gets no summary (w13, w14)
Planner's only candidate for avg_over_time(data[5m]) is a pass-through:
Avg { col: None } has no summary realization and stays a logical pass-through
No avg → sum/count rewrite candidate is proposed, although the backend registers
SemanticEquivalentRewriteStrategy (which contains that rewrite) and sum_over_time/count_over_time
compile to Sum state. w14 also hits the quantile composition rejection described in #701:
composed guarantee (Rank, bound Some(0.013294757464848584), failure probability Some(0.01)) does not satisfy EpsilonDelta { epsilon: 0.01, delta: 0.01 }
3. avg by (job) (data): rewrite proposed but not selected (w16)
Planner searches each sub-expression as a separate group. The root group (the whole
avg by (job) (data)) has two candidates:
| root candidate |
meaning |
status |
pass-through (SketchAlgorithmStrategy: "Avg { col: None } has no summary realization and stays a logical pass-through") |
run the original expression unchanged (KeepPreAsap) |
selected |
rewrite (SemanticEquivalentRewriteStrategy) |
sum by (job) (data) / count by (job) (data) |
unselected |
The rewrite's sum and count sub-groups do choose candidates (exact Sum, exact Count, UnivMon), but
those choices are only used if the root takes the rewrite. Because the root takes the pass-through,
the QueryPlan is a single exact_fallback. Every candidate in logical_selection has
estimated_cost: null, so the choice is not explained by reported costs.
4. count by (job) (data): Count or Cardinality intent? (w15)
PromQL count by (job) (v) counts the elements (series) in each group. ASAPPlanner's PromQL frontend
lowers it to the distinct-count intent:
crates/frontend-promql/src/promql.rs:48 documents count by (d) (…) → Aggregate{[Cardinality], …}
build_over_subtree (promql.rs:593-599) emits AggIntent::Cardinality { col: None } for the outer count
Cardinality is technically correct here: Prometheus does not allow duplicate series label sets, so
the number of elements in an instant vector equals its number of distinct series. We should still
decide whether this should lower to AggIntent::Count or AggIntent::Cardinality.
If it stays Cardinality, it is not implemented anyway. Planner's only candidate is a pass-through,
and the query runs as exact fallback:
cardinality (distinct count) has no summary realization and stays a logical pass-through
Environment
control_plane --example inspect_physical_dag(normalBackendLocalPlanningSnapshot::compilepath)docs/examples/asapquery-compatibility-demo-snapshot.json;source_sample_interval_ms = 1000,horizon_seconds = 3600, nowindow_candidatessupplied.Instant queries use lookback 1s.
sum/count/avgqueries useimplicit_exact; w14 usesEpsilonDelta { epsilon: 0.01, delta: 0.01 }because it contains a quantile.Related: #701 (same snapshot setup).
Workloads and results
Metric
data, scraped every 1s.quantile by (job) (0.9, data)job, tumbling 1s/1s, pane 1ssum by (job) (data)sum(data)avg_over_time(data[5m])exact_fallbackavg_over_time(data[5m]) / quantile_over_time(0.5, data[5m])exact_fallbackcount by (job) (data)exact_fallbackcount(data)exact_fallbackavg by (job) (data)exact_fallbacksum by (job) (sum_over_time(data[5m]))read_materialization→exact_readout→sum by (job)1. Instant
sumfails to compileBoth
sum by (job) (data)andsum(data)fail. The same instant-selector shape is handled threedifferent ways:
quantile by (job) (φ, data)is materialized,count by (job) (data)falls back toexact, and
sum by (job) (data)is a hard compile error. Expected either a supported plan or exactrouting, consistently across aggregations.
2.
avg_over_timegets no summary (w13, w14)Planner's only candidate for
avg_over_time(data[5m])is a pass-through:No avg → sum/count rewrite candidate is proposed, although the backend registers
SemanticEquivalentRewriteStrategy(which contains that rewrite) andsum_over_time/count_over_timecompile to Sum state. w14 also hits the quantile composition rejection described in #701:
3.
avg by (job) (data): rewrite proposed but not selected (w16)Planner searches each sub-expression as a separate group. The root group (the whole
avg by (job) (data)) has two candidates:SketchAlgorithmStrategy: "Avg { col: None } has no summary realization and stays a logical pass-through")KeepPreAsap)SemanticEquivalentRewriteStrategy)sum by (job) (data) / count by (job) (data)The rewrite's
sumandcountsub-groups do choose candidates (exact Sum, exact Count, UnivMon), butthose choices are only used if the root takes the rewrite. Because the root takes the pass-through,
the QueryPlan is a single
exact_fallback. Every candidate inlogical_selectionhasestimated_cost: null, so the choice is not explained by reported costs.4.
count by (job) (data):CountorCardinalityintent? (w15)PromQL
count by (job) (v)counts the elements (series) in each group. ASAPPlanner's PromQL frontendlowers it to the distinct-count intent:
crates/frontend-promql/src/promql.rs:48documentscount by (d) (…)→Aggregate{[Cardinality], …}build_over_subtree(promql.rs:593-599) emitsAggIntent::Cardinality { col: None }for the outercountCardinalityis technically correct here: Prometheus does not allow duplicate series label sets, sothe number of elements in an instant vector equals its number of distinct series. We should still
decide whether this should lower to
AggIntent::CountorAggIntent::Cardinality.If it stays
Cardinality, it is not implemented anyway. Planner's only candidate is a pass-through,and the query runs as exact fallback: