diff --git a/crates/devtools/src/bin/stage_pipeline.rs b/crates/devtools/src/bin/stage_pipeline.rs index 3d5e024c9..bf3518a38 100644 --- a/crates/devtools/src/bin/stage_pipeline.rs +++ b/crates/devtools/src/bin/stage_pipeline.rs @@ -42,8 +42,8 @@ use asap_types::ir::{OperatorNode, QueryRoot}; use asap_types::types::AccuracyTarget; use asap_types::workload::{ AccuracyRequirement, BatchEntry, DataArrival, DataDistribution, DataWorkload, DurationMs, - Evidence, EvidenceSource, LatencyRequirement, PlanningWorkload, Predictability, Query, - QueryLanguage, QueryRecurrence, QueryRequirements, QueryTimeScope, QueryWorkload, Rate, + Evidence, EvidenceSource, LatencyRequirement, MetricType, PlanningWorkload, Predictability, + Query, QueryLanguage, QueryRecurrence, QueryRequirements, QueryTimeScope, QueryWorkload, Rate, RepeatedDemand, RepeatingEntry, RepetitionInterval, RootDemand, TimeSelection, }; use serde_json::{json, Value}; @@ -406,6 +406,8 @@ fn planner_layering_example1() -> PlanningWorkload { ingestion_rate: declared(Rate(1_000_000.0 / 15.0)), input_cardinality: declared(1_000_000), distribution: declared(DataDistribution::Zipf), + // `http_requests_total` is a counter: its samples are never negative. + metric_types: [("http_requests_total".into(), MetricType::Counter)].into(), }), } } diff --git a/crates/integration-tests/tests/planner_layering_example1.rs b/crates/integration-tests/tests/planner_layering_example1.rs index 1e54d0f1e..92bd1806d 100644 --- a/crates/integration-tests/tests/planner_layering_example1.rs +++ b/crates/integration-tests/tests/planner_layering_example1.rs @@ -24,9 +24,9 @@ use asap_types::ir::{ASAPOp, Operator}; use asap_types::types::AccuracyTarget; use asap_types::workload::{ AccuracyRequirement, DataArrival, DataDistribution, DataWorkload, DurationMs, Evidence, - EvidenceSource, LatencyRequirement, PlanningWorkload, Predictability, Query, QueryLanguage, - QueryRequirements, QueryTimeScope, QueryWorkload, Rate, RepeatedDemand, RepeatingEntry, - RepetitionInterval, TimeSelection, + EvidenceSource, LatencyRequirement, MetricType, PlanningWorkload, Predictability, Query, + QueryLanguage, QueryRequirements, QueryTimeScope, QueryWorkload, Rate, RepeatedDemand, + RepeatingEntry, RepetitionInterval, TimeSelection, }; type Payload = Operator; @@ -337,6 +337,8 @@ fn example1_workload() -> PlanningWorkload { ingestion_rate: declared(Rate(1_000_000.0 / 15.0)), input_cardinality: declared(1_000_000), distribution: declared(DataDistribution::Zipf), + // `http_requests_total` is a counter: its samples are never negative. + metric_types: [("http_requests_total".into(), MetricType::Counter)].into(), }), } } @@ -515,12 +517,31 @@ fn snake_case(name: &str) -> String { out } +/// Example 1 with `http_requests_total` declared `metric_type`, or undeclared. +fn example1_workload_with(metric_type: Option) -> PlanningWorkload { + let mut workload = example1_workload(); + let data = workload.data_workload.as_mut().expect("data workload"); + data.metric_types = metric_type + .map(|t| [("http_requests_total".to_string(), t)].into()) + .unwrap_or_default(); + workload +} + fn pipeline() -> ( PlanningWorkload, Vec, Vec, ) { - let workload = example1_workload(); + pipeline_for(example1_workload()) +} + +fn pipeline_for( + workload: PlanningWorkload, +) -> ( + PlanningWorkload, + Vec, + Vec, +) { let logical = stage1_logical_asap(&workload, &stage0_logical(&workload)); let physical = stage2_physical(&workload, &logical); (workload, logical, physical) @@ -898,13 +919,11 @@ fn compile_in_runtime(p: &PhysicalCandidate) -> Result<(), String> { .map_err(|e| format!("{} ({}): {e}", p.id, p.label)) } -/// Runtime capability check (added by the implementer, not part of the -/// spec): the physical planner compiles every candidate Stage 3 finds valid, -/// and rejects the invalid ones (Count-Min over weights not proven -/// non-negative) for the same reason Stage 3 gives. -#[test] -fn stage2_runtime_compiles_exactly_the_candidates_stage3_finds_valid() { - let (workload, _, physical) = pipeline(); +/// The physical planner compiles every candidate Stage 3 finds valid, and +/// rejects the invalid ones (Count-Min over weights not proven non-negative) +/// for the same reason Stage 3 gives. Returns the number of invalid ones. +fn assert_runtime_agrees_with_stage3(workload: PlanningWorkload) -> usize { + let (workload, _, physical) = pipeline_for(workload); let selection = stage3_select(&workload, &physical, PlanningModels::builtin()); let invalid: BTreeMap<_, _> = selection .rejected @@ -912,7 +931,6 @@ fn stage2_runtime_compiles_exactly_the_candidates_stage3_finds_valid() { .filter(|r| !r.valid) .map(|r| (r.id.as_str(), r.reason.as_str())) .collect(); - assert_eq!(invalid.len(), 24, "the Count-Min + heap candidates"); for p in &physical { let compiled = compile_in_runtime(p); match invalid.get(p.id.as_str()) { @@ -931,6 +949,28 @@ fn stage2_runtime_compiles_exactly_the_candidates_stage3_finds_valid() { } } } + invalid.len() +} + +/// Runtime capability check (added by the implementer, not part of the +/// spec): with `http_requests_total` declared a counter, every candidate, +/// Count-Min + heap included, is valid in Stage 3 and compiles. +#[test] +fn stage2_runtime_compiles_every_candidate_over_a_declared_counter() { + assert_eq!(assert_runtime_agrees_with_stage3(example1_workload()), 0); +} + +/// Without the counter declaration, or with a gauge, the Count-Min + heap +/// candidates are invalid in Stage 3 and the runtime rejects them. +#[test] +fn stage2_count_min_needs_a_counter_declaration() { + for metric_type in [None, Some(MetricType::Gauge)] { + assert_eq!( + assert_runtime_agrees_with_stage3(example1_workload_with(metric_type)), + 24, + "{metric_type:?}: the Count-Min + heap candidates" + ); + } } /// A CountSketch+heap top-k readout compiles: the IR's derived readout schema @@ -1008,7 +1048,7 @@ fn stage3_selects_cheapest_valid() { /// Per-second cost keeps Example 1's ranking: both panels repeat every /// 10 s and everything runs at query time, so every candidate costs 0.1 × -/// its per-evaluation cost, and P58 still wins at 52.201 × 0.1 per second. +/// its per-evaluation cost, and P60 still wins at 46.201 × 0.1 per second. #[test] fn stage3_per_second_cost_keeps_the_ranking() { let (workload, _, physical) = pipeline(); @@ -1024,14 +1064,14 @@ fn stage3_per_second_cost_keeps_the_ranking() { entry.demand = RepeatedDemand::FixedInterval(RepetitionInterval(1_000)); } let per_evaluation = stage3_select(&every_second, &physical, PlanningModels::builtin()); - assert_eq!(per_second.selected, "P58"); - assert_eq!(per_evaluation.selected, "P58"); + assert_eq!(per_second.selected, "P60"); + assert_eq!(per_evaluation.selected, "P60"); for (id, cost) in &per_second.costs { let expected = 0.1 * per_evaluation.costs[id].total; assert!((cost.total - expected).abs() <= 1e-9 * expected, "{id}"); } - let best = per_second.costs["P58"].total; - assert!((best - 5.2201).abs() < 1e-3, "{best}"); + let best = per_second.costs["P60"].total; + assert!((best - 4.6201).abs() < 1e-3, "{best}"); } /// Every node is charged exactly once, so a shared input is costed once for @@ -1069,8 +1109,8 @@ fn stage3_charges_each_node_once() { } /// Sharing the input never costs more than reading it separately, for the -/// same local choices. Count-Min + heap is invalid here and has no cost -/// (Hydra: see `stage1_q2_summary_families_are_heap_sketches_and_hydra`). +/// same local choices (Hydra: see +/// `stage1_q2_summary_families_are_heap_sketches_and_hydra`). #[test] fn stage3_shared_input_is_not_costlier() { let (workload, _, physical) = pipeline(); @@ -1085,7 +1125,9 @@ fn stage3_shared_input_is_not_costlier() { .collect(); for option in [ Q2Option::Exact, + Q2Option::CountMinHeapPerJob, Q2Option::CountSketchHeapPerJob, + Q2Option::WholeCountMinHeapPerJob, Q2Option::WholeCountSketchHeapPerJob, ] { assert!( diff --git a/crates/logical-optimizer/src/pass1/logical_candidates.rs b/crates/logical-optimizer/src/pass1/logical_candidates.rs index 8eb1a417e..741b42b27 100644 --- a/crates/logical-optimizer/src/pass1/logical_candidates.rs +++ b/crates/logical-optimizer/src/pass1/logical_candidates.rs @@ -4,10 +4,10 @@ //! target, not ranked plans or accuracy certificates. Workload composition and //! physical planning consume this inventory later; empirical models belong to //! selection. The legacy search API remains until planner cutover. -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::rc::Rc; -use asap_types::ir::operator::{AggIntent, Reduction}; +use asap_types::ir::operator::{AggIntent, Reduction, Source}; use asap_types::ir::scalar::ColumnRef; use asap_types::ir::schema::Schema; use asap_types::ir::schema::{ @@ -17,6 +17,7 @@ use asap_types::ir::schema::{ }; use asap_types::ir::{ASAPOp, NonASAPOp, Operator, OperatorNode, QueryRoot, SchemaDerivationError}; use asap_types::types::AccuracyTarget; +use asap_types::workload::MetricType; use thiserror::Error; use crate::pass1::replacement::{ @@ -34,6 +35,9 @@ pub struct LocalLogicalTarget { /// not computed and has no choice of its own (#509 whole-expression /// realization). `None`: the alternative reads this target's input. pub absorbs: Vec>, + /// Whether the target's input values are [`counter_samples`]. Absorbing + /// alternatives read the input's own input, which then is too. + pub counter_input: bool, } /// Compact Pass 1 inventory; roots and nested producer dependencies are retained. @@ -103,6 +107,7 @@ pub fn local_realizations_for_intent( /// Multi-measure aggregates remain intact pending a semantics-preserving split. pub fn enumerate_local_logical_candidates( roots: Vec<(Id, QueryRoot)>, + metric_types: &BTreeMap, ) -> Result, LogicalCandidateError> { let mut seen = HashSet::new(); let mut targets = Vec::new(); @@ -132,6 +137,10 @@ pub fn enumerate_local_logical_candidates( targets.push(LocalLogicalTarget { absorbs: vec![None; alternatives.len()], alternatives, + counter_input: node + .children() + .iter() + .all(|child| counter_samples(child, metric_types)), target: node, }); } @@ -410,7 +419,10 @@ pub fn compose_logical_candidate( .get(index) .map(|alternative| { let absorbs = target.absorbs[index].is_some(); - (Rc::as_ptr(&target.target), (alternative, absorbs)) + ( + Rc::as_ptr(&target.target), + (alternative, absorbs, target.counter_input), + ) }) .ok_or(LogicalCandidateError::InvalidChoice) }) @@ -439,8 +451,9 @@ pub fn compose_logical_candidate( } type Memo = HashMap<*const OperatorNode, Rc>; -/// Each target's chosen alternative, and whether it absorbs the target beneath. -type Chosen<'a> = HashMap<*const OperatorNode, (&'a Realization, bool)>; +/// Each target's chosen alternative, whether it absorbs the target beneath, +/// and its `counter_input`. +type Chosen<'a> = HashMap<*const OperatorNode, (&'a Realization, bool, bool)>; fn rewrite( node: &Rc, @@ -458,8 +471,10 @@ fn rewrite( .iter() .any(|child| !Rc::ptr_eq(child, &memo[&Rc::as_ptr(child)])); let rebuilt = match chosen.get(&Rc::as_ptr(node)) { - Some((realization, absorbs)) if **realization != Realization::PassThrough => { - realize(node, realization, *absorbs, memo)? + Some((realization, absorbs, counter_input)) + if **realization != Realization::PassThrough => + { + realize(node, realization, *absorbs, *counter_input, memo)? } _ if changed => Rc::new(node.with_new_children(|child| memo[&Rc::as_ptr(child)].clone())?), _ => node.clone(), @@ -472,6 +487,7 @@ fn realize( target: &OperatorNode, realization: &Realization, absorbs: bool, + counter_input: bool, memo: &Memo, ) -> Result, LogicalCandidateError> { let Some(NonASAPOp::Aggregate { @@ -519,10 +535,19 @@ fn realize( ), _ => return Err(LogicalCandidateError::Unsupported("summary family")), }; - let input = match whole { + let mut input = match whole { Some((_, update)) => update, None => summary_update(intent, &family, reduction, &child.schema)?, }; + if counter_input + && input.item.is_some() + && input.weight == SummaryInputExpr::Column(ColumnRef::SampleValue) + && input.weight_domain == WeightDomain::UnknownOrSigned + { + input.weight_domain = WeightDomain::NonNegative { + proof: NonNegativeWeightProof::CounterSamples, + }; + } let state = OperatorNode::new(Operator::ASAP(ASAPOp::SummaryAgg { child: child.clone(), family, @@ -542,6 +567,28 @@ fn realize( Ok(OperatorNode::new_shared(Operator::ASAP(evaluation))?) } +/// Whether every value `node` outputs is a sample of a metric declared a +/// counter, or a sum of such samples: never negative. Only a time-range +/// selection and a plain sum preserve that; any other operator (arithmetic +/// included) ends the proof. Read off the frontend DAG, this also holds for +/// the composed candidate because a sum has only exact realizations. +fn counter_samples(node: &OperatorNode, metric_types: &BTreeMap) -> bool { + match node.non_asap() { + Some(NonASAPOp::Scan { + source: Source::TimeSeries { metric }, + .. + }) => metric_types.get(metric) == Some(&MetricType::Counter), + Some(NonASAPOp::TimeRange { child, .. }) => counter_samples(child, metric_types), + Some(NonASAPOp::Aggregate { + measures, child, .. + }) => { + matches!(measures.as_slice(), [AggIntent::Sum { col: None }]) + && counter_samples(child, metric_types) + } + _ => false, + } +} + /// What each input row contributes, following the legacy realization rules: /// heap sketches rank series identities, frequency sketches count values, and /// every other family reads the measure's input column. @@ -644,8 +691,11 @@ mod tests { }, ); let root = asap_types::ir::schema_support::with_promql_series_identity(&root).unwrap(); - let inventory = - enumerate_local_logical_candidates(vec![(0, QueryRoot::Operator(root))]).unwrap(); + let inventory = enumerate_local_logical_candidates( + vec![(0, QueryRoot::Operator(root))], + &BTreeMap::new(), + ) + .unwrap(); let topk = inventory .targets .iter() @@ -696,8 +746,11 @@ mod tests { }, ); let root = asap_types::ir::schema_support::with_promql_series_identity(&root).unwrap(); - let inventory = - enumerate_local_logical_candidates(vec![(0, QueryRoot::Operator(root))]).unwrap(); + let inventory = enumerate_local_logical_candidates( + vec![(0, QueryRoot::Operator(root))], + &BTreeMap::new(), + ) + .unwrap(); let (topk, inner) = inventory .targets .iter() @@ -728,6 +781,112 @@ mod tests { } } + /// The weight domain of every heap-sketch update (Count-Min or + /// CountSketch + heap) in every candidate of `query`. + fn heap_weight_domains(query: &str, metric_types: &[(&str, MetricType)]) -> Vec { + let root = lower_promql( + query, + AccuracyTarget::EpsilonDelta { + epsilon: 0.01, + delta: 0.001, + }, + ); + let root = asap_types::ir::schema_support::with_promql_series_identity(&root).unwrap(); + let metric_types = metric_types + .iter() + .map(|(metric, kind)| (metric.to_string(), *kind)) + .collect(); + let inventory = + enumerate_local_logical_candidates(vec![(0, QueryRoot::Operator(root))], &metric_types) + .unwrap(); + let mut domains = Vec::new(); + for choice in enumerate_choices(&inventory, usize::MAX) { + for (_, root) in compose_logical_candidate(&inventory, &choice).unwrap() { + let QueryRoot::Operator(root) = root else { + panic!("operator root") + }; + for node in OperatorNode::reachable(&root) { + if let Operator::ASAP(ASAPOp::SummaryAgg { + family: FieldDataType::Sketch(kind, _), + input, + .. + }) = &node.operator + { + if matches!( + kind.algorithm(), + SketchAlgorithm::CmsWithHeap | SketchAlgorithm::CountSketchWithHeap + ) { + domains.push(input.weight_domain.clone()); + } + } + } + } + } + domains + } + + const COUNTER_PROOF: WeightDomain = WeightDomain::NonNegative { + proof: NonNegativeWeightProof::CounterSamples, + }; + + /// Raw samples of a declared counter, and their `sum_over_time`, are + /// proven non-negative: the whole-expression heaps read the samples, the + /// others read the sums. + #[test] + fn declared_counter_samples_prove_heap_weights_non_negative() { + let domains = heap_weight_domains( + "topk by (job) (10, sum_over_time(m[1m]))", + &[("m", MetricType::Counter)], + ); + // (CMS, CountSketch) × (raw sum, Sum accumulator) + 2 whole-expression. + assert_eq!(domains.len(), 6); + assert!(domains.iter().all(|d| *d == COUNTER_PROOF), "{domains:?}"); + } + + /// No proof without a counter declaration: an undeclared metric (whatever + /// its name), a gauge, or another metric declared a counter. + #[test] + fn undeclared_or_gauge_samples_are_not_proven_non_negative() { + for (query, metric_types) in [ + ("topk by (job) (10, sum_over_time(m_total[1m]))", vec![]), + ( + "topk by (job) (10, sum_over_time(m[1m]))", + vec![("m", MetricType::Gauge)], + ), + ( + "topk by (job) (10, sum_over_time(m[1m]))", + vec![("other", MetricType::Counter)], + ), + ] { + let domains = heap_weight_domains(query, &metric_types); + assert_eq!(domains.len(), 6, "{query}"); + assert!( + domains.iter().all(|d| *d == WeightDomain::UnknownOrSigned), + "{query} {metric_types:?}: {domains:?}" + ); + } + } + + /// Counter samples and their sums are proven; arithmetic over them, + /// which can go negative, and a gauge are not. + #[test] + fn counter_samples_end_at_arithmetic() { + let metric_types = BTreeMap::from([ + ("m".to_string(), MetricType::Counter), + ("g".to_string(), MetricType::Gauge), + ]); + for (query, proven) in [ + ("sum_over_time(m[1m])", true), + ("sum by (job) (sum_over_time(m[1m]))", true), + ("sum_over_time(m[1m]) - 100", false), + ("-sum_over_time(m[1m])", false), + ("sum_over_time(g[1m])", false), + ] { + let root = lower_promql(query, AccuracyTarget::Exact); + assert_eq!(counter_samples(&root, &metric_types), proven, "{query}"); + } + } + /// Approximate requests must retain the exact execution alternative too. #[test] fn approximate_count_keeps_exact_and_universal_choices() { diff --git a/crates/logical-optimizer/src/pass2/identical_expressions.rs b/crates/logical-optimizer/src/pass2/identical_expressions.rs index 2baefe7b9..56361cdc2 100644 --- a/crates/logical-optimizer/src/pass2/identical_expressions.rs +++ b/crates/logical-optimizer/src/pass2/identical_expressions.rs @@ -8,11 +8,12 @@ //! [`share_common_sub_dags`]. A target that sharing merges is one target in //! the shared form, so its queries take the same alternative. -use std::collections::HashSet; +use std::collections::{BTreeMap, HashSet}; use std::rc::Rc; use asap_types::ir::cse::share_common_sub_dags; use asap_types::ir::{OperatorNode, QueryRoot}; +use asap_types::workload::MetricType; use crate::pass1::logical_candidates::{ enumerate_local_logical_candidates, LocalLogicalCandidates, LogicalCandidateError, @@ -30,16 +31,17 @@ pub struct SharingVariant { /// variant first, then the shared one when sharing merges at least one node. pub fn stage1_logical_candidates( roots: Vec<(Id, QueryRoot)>, + metric_types: &BTreeMap, ) -> Result>, LogicalCandidateError> { let shared = share_identical_expressions(&roots); let mut variants = vec![SharingVariant { shared: false, - inventory: enumerate_local_logical_candidates(roots)?, + inventory: enumerate_local_logical_candidates(roots, metric_types)?, }]; if let Some(roots) = shared { variants.push(SharingVariant { shared: true, - inventory: enumerate_local_logical_candidates(roots)?, + inventory: enumerate_local_logical_candidates(roots, metric_types)?, }); } Ok(variants) @@ -103,10 +105,13 @@ mod tests { /// shared variant, with the same targets in each. #[test] fn identical_input_adds_a_shared_variant() { - let variants = stage1_logical_candidates(roots(&[ - "sum by (job) (rate(m[1m]))", - "topk by (job) (10, sum_over_time(m[1m]))", - ])) + let variants = stage1_logical_candidates( + roots(&[ + "sum by (job) (rate(m[1m]))", + "topk by (job) (10, sum_over_time(m[1m]))", + ]), + &BTreeMap::new(), + ) .unwrap(); assert_eq!( variants.iter().map(|v| v.shared).collect::>(), @@ -134,8 +139,11 @@ mod tests { /// Queries with nothing in common have no shared variant. #[test] fn nothing_identical_adds_no_variant() { - let variants = - stage1_logical_candidates(roots(&["sum(rate(a[1m]))", "sum(rate(b[1m]))"])).unwrap(); + let variants = stage1_logical_candidates( + roots(&["sum(rate(a[1m]))", "sum(rate(b[1m]))"]), + &BTreeMap::new(), + ) + .unwrap(); assert_eq!(variants.len(), 1); assert!(!variants[0].shared); } diff --git a/crates/logical-optimizer/tests/logical_candidates.rs b/crates/logical-optimizer/tests/logical_candidates.rs index 744070684..32cb5b610 100644 --- a/crates/logical-optimizer/tests/logical_candidates.rs +++ b/crates/logical-optimizer/tests/logical_candidates.rs @@ -127,7 +127,7 @@ fn scalar_root_producers_are_discovered_once() { ), ("relation", QueryRoot::Operator(producer.clone())), ]; - let candidates = enumerate_local_logical_candidates(roots).unwrap(); + let candidates = enumerate_local_logical_candidates(roots, &Default::default()).unwrap(); assert_eq!(candidates.roots.len(), 2); for (_, root) in &candidates.roots { root.validate_structure().unwrap(); @@ -171,8 +171,11 @@ fn promql_lowering_reaches_local_candidates_without_execution_timing() { }), }; let roots = asap_frontend_promql::lower_promql_query_workload(&workload, 0).unwrap(); - let candidates = - enumerate_local_logical_candidates(roots.into_iter().enumerate().collect()).unwrap(); + let candidates = enumerate_local_logical_candidates( + roots.into_iter().enumerate().collect(), + &Default::default(), + ) + .unwrap(); assert!(candidates .targets .iter() @@ -198,7 +201,10 @@ fn assigned_timing_and_invalid_accuracy_are_rejected() { .clone(); producer.timing = Some(asap_types::ir::properties::ExecutionTiming::QueryTime); assert!(matches!( - enumerate_local_logical_candidates(vec![(0, QueryRoot::Operator(Rc::new(producer)))]), + enumerate_local_logical_candidates( + vec![(0, QueryRoot::Operator(Rc::new(producer)))], + &Default::default() + ), Err(LogicalCandidateError::AssignedTiming) )); for target in [ @@ -243,9 +249,11 @@ fn composed_candidate_replaces_chosen_target_with_summary_evaluation() { cols: vec![0], accuracy: approximate(), }); - let inventory = - enumerate_local_logical_candidates(vec![(0, QueryRoot::Operator(producer.clone()))]) - .unwrap(); + let inventory = enumerate_local_logical_candidates( + vec![(0, QueryRoot::Operator(producer.clone()))], + &Default::default(), + ) + .unwrap(); let exact = compose_logical_candidate(&inventory, &[0]).unwrap(); assert!(matches!(&exact[0].1, QueryRoot::Operator(node) if Rc::ptr_eq(node, &producer))); diff --git a/crates/physical-optimizer/src/implementation/physical_candidates.rs b/crates/physical-optimizer/src/implementation/physical_candidates.rs index 6963ceedf..107f64c48 100644 --- a/crates/physical-optimizer/src/implementation/physical_candidates.rs +++ b/crates/physical-optimizer/src/implementation/physical_candidates.rs @@ -245,6 +245,7 @@ mod tests { let inventory = asap_logical_optimizer::pass1::logical_candidates::enumerate_local_logical_candidates( vec![(0, QueryRoot::Operator(root))], + &Default::default(), ) .unwrap(); // A summary (the last alternative) for every target. diff --git a/crates/plan-selection/src/lib.rs b/crates/plan-selection/src/lib.rs index f06774fb4..dd8d63d35 100644 --- a/crates/plan-selection/src/lib.rs +++ b/crates/plan-selection/src/lib.rs @@ -924,7 +924,7 @@ pub fn plan_stages( models: PlanningModels<'_>, display: usize, ) -> Result, SelectionError> { - let stage1 = stage1_logical_candidates(roots)?; + let stage1 = stage1_logical_candidates(roots, &data.metric_types)?; let plan = select_plan(&stage1, demand, data, models)?; let enumeration = match display { 0 => None, @@ -1553,6 +1553,12 @@ mod tests { /// Exact (P1), CMS+heap (P2) and CountSketch+heap (P3) realizations of /// one approximate top-k query, in Pass 1 catalog order. fn candidates() -> Vec { + candidates_with(&Default::default()) + } + + fn candidates_with( + metric_types: &BTreeMap, + ) -> Vec { let root = lower_promql( "topk by (job) (10, sum_over_time(m[1m]))", AccuracyTarget::EpsilonDelta { @@ -1563,6 +1569,7 @@ mod tests { let inventory = asap_logical_optimizer::pass1::logical_candidates::enumerate_local_logical_candidates( vec![(0, QueryRoot::Operator(root))], + metric_types, ) .unwrap(); let topk = inventory @@ -1645,6 +1652,33 @@ mod tests { assert!(p2.reason.contains("non-negative"), "{}", p2.reason); } + /// Count-Min over samples of a declared counter is valid: Stage 3 prices it. + #[test] + fn count_min_over_declared_counter_samples_is_valid() { + let target = AccuracyTarget::EpsilonDelta { + epsilon: 0.01, + delta: 0.001, + }; + let counter = [("m".to_string(), asap_types::workload::MetricType::Counter)].into(); + let selection = stage3_select( + &candidates_with(&counter), + &[every_10s(Some(target))], + &data(), + PlanningModels::builtin(), + ) + .unwrap(); + assert!( + selection.costs.contains_key("P2"), + "{:?}", + selection.rejected + ); + assert!( + selection.rejected.iter().all(|r| r.valid), + "{:?}", + selection.rejected + ); + } + fn inventory(queries: &[&str]) -> LocalLogicalCandidates { let target = AccuracyTarget::EpsilonDelta { epsilon: 0.01, @@ -1660,8 +1694,11 @@ mod tests { (i, QueryRoot::Operator(root)) }) .collect(); - asap_logical_optimizer::pass1::logical_candidates::enumerate_local_logical_candidates(roots) - .unwrap() + asap_logical_optimizer::pass1::logical_candidates::enumerate_local_logical_candidates( + roots, + &Default::default(), + ) + .unwrap() } fn no_targets(inventory: &LocalLogicalCandidates) -> Vec { @@ -2183,7 +2220,7 @@ mod tests { (i, QueryRoot::Operator(root)) }) .collect(); - let stage1 = stage1_logical_candidates(roots).unwrap(); + let stage1 = stage1_logical_candidates(roots, &Default::default()).unwrap(); let data = DataWorkload { ingestion_rate: Evidence { value: Some(Rate(1_000_000.0 / 15.0)), diff --git a/crates/planner/tests/e2e_plan.rs b/crates/planner/tests/e2e_plan.rs index 3a54cd308..efd6151b5 100644 --- a/crates/planner/tests/e2e_plan.rs +++ b/crates/planner/tests/e2e_plan.rs @@ -126,7 +126,7 @@ async fn facade_plans_match_exhaustive_stage_pipeline_selection() { roots.push((index, QueryRoot::Operator(expr))); targets.push(asap_types::workload::RootDemand::from(&entry)); } - let inventory = stage1_logical_candidates(roots).expect("Stage 1"); + let inventory = stage1_logical_candidates(roots, &Default::default()).expect("Stage 1"); let data = workload.data_workload.clone().unwrap_or_default(); let enumeration = select_exhaustive( &inventory, diff --git a/crates/planner/tests/stage_pipeline_selection.rs b/crates/planner/tests/stage_pipeline_selection.rs index 6d2a9c0e5..ac4fbeded 100644 --- a/crates/planner/tests/stage_pipeline_selection.rs +++ b/crates/planner/tests/stage_pipeline_selection.rs @@ -76,6 +76,7 @@ fn example1() -> PlanningWorkload { ingestion_rate: declared(Rate(1_000_000.0 / 15.0)), input_cardinality: declared(1_000_000), distribution: declared(DataDistribution::Zipf), + metric_types: Default::default(), }), } } @@ -129,7 +130,7 @@ fn promql_inventory(workload: &PlanningWorkload) -> Inventory { QueryRoot::Scalar(_) => panic!("operator roots"), }) .collect(); - stage1_logical_candidates(roots).expect("Stage 1") + stage1_logical_candidates(roots, &Default::default()).expect("Stage 1") } fn targets(workload: &PlanningWorkload) -> Vec { @@ -270,7 +271,7 @@ async fn sql_dp_equals_exhaustive() { .expect("lowers"); roots.push((index, QueryRoot::Operator(root))); } - let inventory = stage1_logical_candidates(roots).expect("Stage 1"); + let inventory = stage1_logical_candidates(roots, &Default::default()).expect("Stage 1"); assert_dp_matches_exhaustive(&inventory, &workload, 15); } diff --git a/crates/types/src/ir/schema/state_type.rs b/crates/types/src/ir/schema/state_type.rs index 8146b652f..0b2f4c8b1 100644 --- a/crates/types/src/ir/schema/state_type.rs +++ b/crates/types/src/ir/schema/state_type.rs @@ -593,6 +593,10 @@ pub enum NonNegativeWeightProof { /// PromQL counter reset correction produces a non-negative increase; rate /// divides that increase by a positive duration. ResetAwareCounterDerivative, + /// Samples of a metric declared a counter + /// ([`MetricType::Counter`](crate::workload::MetricType::Counter)), or + /// sums of them: a counter sample is never negative. + CounterSamples, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/crates/types/src/workload/mod.rs b/crates/types/src/workload/mod.rs index 6e493f9b7..3915ea439 100644 --- a/crates/types/src/workload/mod.rs +++ b/crates/types/src/workload/mod.rs @@ -2,6 +2,8 @@ pub mod parsed_workload; pub mod resources; use crate::types::AccuracyTarget; +use std::collections::BTreeMap; + use serde::{Deserialize, Serialize}; // ── Query surface ───────────────────────────────────────────────────────────── @@ -561,6 +563,22 @@ pub struct DataWorkload { pub ingestion_rate: Evidence, pub input_cardinality: Evidence, pub distribution: Evidence, + /// Declared type of each metric, by metric name (Prometheus `# TYPE` + /// metadata). The planner never infers a type from a name such as + /// `_total`; an undeclared metric's samples may take any value. + #[serde(default)] + pub metric_types: BTreeMap, +} + +/// The Prometheus type of a metric's samples. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum MetricType { + /// Starts at zero and only increases, or resets to zero: every sample + /// is non-negative. + Counter, + /// May take any value. + Gauge, } // ── Top-level workload ──────────────────────────────────────────────────────── diff --git a/docs/design_docs/architecture/input-output-workflow.md b/docs/design_docs/architecture/input-output-workflow.md index 133914f21..8d1418251 100644 --- a/docs/design_docs/architecture/input-output-workflow.md +++ b/docs/design_docs/architecture/input-output-workflow.md @@ -224,6 +224,7 @@ struct DataWorkload { ingestion_rate: Evidence, input_cardinality: Evidence, distribution: Evidence, + metric_types: BTreeMap, } ``` @@ -235,6 +236,7 @@ struct DataWorkload { | `ingestion_rate` | Optional evidence | Updates per second used to price continuous maintenance. It must be finite and non-negative; at-rest data cannot declare a positive rate. | | `input_cardinality` | Optional evidence | Input row/sample count used by applicable sizing, accuracy, or cost rules. | | `distribution` | Optional evidence | `Zipf`, `Uniform`, or `Bursty` key distribution used only by rules that explicitly consume it. | +| `metric_types` | Optional; defaults to empty | Declared `Counter` or `Gauge` type per metric name. A counter's samples are never negative, so Count-Min over them, or over their sums, is admissible. An undeclared metric is not treated as a counter, whatever its name. | ##### `Evidence` fields diff --git a/docs/design_docs/proposals/planner-layering-example1-acceptance.md b/docs/design_docs/proposals/planner-layering-example1-acceptance.md index 2f110708e..cedf0f069 100644 --- a/docs/design_docs/proposals/planner-layering-example1-acceptance.md +++ b/docs/design_docs/proposals/planner-layering-example1-acceptance.md @@ -26,6 +26,8 @@ window summary for either query; in Stage 2, the one where both queries are Shared data workload: `continuously_ingesting`, 15 s ingestion interval, 1,000,000 series, about 66,667 samples/s, `zipf`, volume unknown. +`http_requests_total` is declared a counter (`metric_types`), so its samples +are known to be non-negative. | Query | Repeats | `lookback` | `as_of` | Accuracy | Latency | |---|---|---|---|---|---| @@ -104,8 +106,10 @@ Invariants: merge node, because the MVP has no window summaries. * No node runs at ingestion time, because the MVP has no materialization. * The runtime's physical planner compiles every candidate Stage 3 finds - valid, and rejects the 24 Count-Min + heap candidates for the reason Stage 3 - gives: their update weights are not proven non-negative. + valid. With the counter declaration that is all 64. Without it, or with + `http_requests_total` declared a gauge, the runtime rejects the 24 + Count-Min + heap candidates for the reason Stage 3 gives: their update + weights are not proven non-negative. ### Candidates for manual review @@ -114,76 +118,77 @@ Generated from `tools/dag-viewer/examples/planner-layering-example1.json`. | Id | Label | Q1 choice | Q2 choice | Input | Stage 3 outcome | Reason | |---|---|---|---|---|---|---| -| P1 (L1) | Q1 exact · Q2 exact | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.640 vs 5.220 cost/s | -| P2 (L2) | Q1 exact · Q2 exact (Sum acc) | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 8.340 vs 5.220 cost/s | -| P3 (L3) | Q1 exact · Q2 CMS+heap | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P4 (L4) | Q1 exact · Q2 CMS+heap (Sum acc) | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P5 (L5) | Q1 exact · Q2 CountSketch+heap | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.840 vs 5.220 cost/s | -| P6 (L6) | Q1 exact · Q2 CountSketch+heap (Sum acc) | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.540 vs 5.220 cost/s | -| P7 (L7) | Q1 exact · Q2 whole-expression CMS+heap | rate: raw; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P8 (L8) | Q1 exact · Q2 whole-expression CountSketch+heap | rate: raw; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.840 vs 5.220 cost/s | -| P9 (L9) | Q1 exact (Rate acc) · Q2 exact | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.340 vs 5.220 cost/s | -| P10 (L10) | Q1 exact (Rate acc) · Q2 exact (Sum acc) | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 8.040 vs 5.220 cost/s | -| P11 (L11) | Q1 exact (Rate acc) · Q2 CMS+heap | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P12 (L12) | Q1 exact (Rate acc) · Q2 CMS+heap (Sum acc) | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P13 (L13) | Q1 exact (Rate acc) · Q2 CountSketch+heap | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.540 vs 5.220 cost/s | -| P14 (L14) | Q1 exact (Rate acc) · Q2 CountSketch+heap (Sum acc) | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.240 vs 5.220 cost/s | -| P15 (L15) | Q1 exact (Rate acc) · Q2 whole-expression CMS+heap | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P16 (L16) | Q1 exact (Rate acc) · Q2 whole-expression CountSketch+heap | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.540 vs 5.220 cost/s | -| P17 (L17) | Q1 exact (Sum acc) · Q2 exact | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.540 vs 5.220 cost/s | -| P18 (L18) | Q1 exact (Sum acc) · Q2 exact (Sum acc) | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 8.240 vs 5.220 cost/s | -| P19 (L19) | Q1 exact (Sum acc) · Q2 CMS+heap | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P20 (L20) | Q1 exact (Sum acc) · Q2 CMS+heap (Sum acc) | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P21 (L21) | Q1 exact (Sum acc) · Q2 CountSketch+heap | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.740 vs 5.220 cost/s | -| P22 (L22) | Q1 exact (Sum acc) · Q2 CountSketch+heap (Sum acc) | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.440 vs 5.220 cost/s | -| P23 (L23) | Q1 exact (Sum acc) · Q2 whole-expression CMS+heap | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P24 (L24) | Q1 exact (Sum acc) · Q2 whole-expression CountSketch+heap | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.740 vs 5.220 cost/s | -| P25 (L25) | Q1 exact (Sum acc, Rate acc) · Q2 exact | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.240 vs 5.220 cost/s | -| P26 (L26) | Q1 exact (Sum acc, Rate acc) · Q2 exact (Sum acc) | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 7.940 vs 5.220 cost/s | -| P27 (L27) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P28 (L28) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap (Sum acc) | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P29 (L29) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.440 vs 5.220 cost/s | -| P30 (L30) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap (Sum acc) | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.140 vs 5.220 cost/s | -| P31 (L31) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CMS+heap | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P32 (L32) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CountSketch+heap | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.440 vs 5.220 cost/s | -| P33 (L33) | Q1 exact · Q2 exact · shared input | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.920 vs 5.220 cost/s | -| P34 (L34) | Q1 exact · Q2 exact (Sum acc) · shared input | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | valid, costlier | 5.620 vs 5.220 cost/s | -| P35 (L35) | Q1 exact · Q2 CMS+heap · shared input | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P36 (L36) | Q1 exact · Q2 CMS+heap (Sum acc) · shared input | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P37 (L37) | Q1 exact · Q2 CountSketch+heap · shared input | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 17.120 vs 5.220 cost/s | -| P38 (L38) | Q1 exact · Q2 CountSketch+heap (Sum acc) · shared input | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.820 vs 5.220 cost/s | -| P39 (L39) | Q1 exact · Q2 whole-expression CMS+heap · shared input | rate: raw; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P40 (L40) | Q1 exact · Q2 whole-expression CountSketch+heap · shared input | rate: raw; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 54.120 vs 5.220 cost/s | -| P41 (L41) | Q1 exact (Rate acc) · Q2 exact · shared input | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.620 vs 5.220 cost/s | -| P42 (L42) | Q1 exact (Rate acc) · Q2 exact (Sum acc) · shared input | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | valid, costlier | 5.320 vs 5.220 cost/s | -| P43 (L43) | Q1 exact (Rate acc) · Q2 CMS+heap · shared input | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P44 (L44) | Q1 exact (Rate acc) · Q2 CMS+heap (Sum acc) · shared input | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P45 (L45) | Q1 exact (Rate acc) · Q2 CountSketch+heap · shared input | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 16.820 vs 5.220 cost/s | -| P46 (L46) | Q1 exact (Rate acc) · Q2 CountSketch+heap (Sum acc) · shared input | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.520 vs 5.220 cost/s | -| P47 (L47) | Q1 exact (Rate acc) · Q2 whole-expression CMS+heap · shared input | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P48 (L48) | Q1 exact (Rate acc) · Q2 whole-expression CountSketch+heap · shared input | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 53.820 vs 5.220 cost/s | -| P49 (L49) | Q1 exact (Sum acc) · Q2 exact · shared input | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.820 vs 5.220 cost/s | -| P50 (L50) | Q1 exact (Sum acc) · Q2 exact (Sum acc) · shared input | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | valid, costlier | 5.520 vs 5.220 cost/s | -| P51 (L51) | Q1 exact (Sum acc) · Q2 CMS+heap · shared input | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P52 (L52) | Q1 exact (Sum acc) · Q2 CMS+heap (Sum acc) · shared input | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P53 (L53) | Q1 exact (Sum acc) · Q2 CountSketch+heap · shared input | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 17.020 vs 5.220 cost/s | -| P54 (L54) | Q1 exact (Sum acc) · Q2 CountSketch+heap (Sum acc) · shared input | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.720 vs 5.220 cost/s | -| P55 (L55) | Q1 exact (Sum acc) · Q2 whole-expression CMS+heap · shared input | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P56 (L56) | Q1 exact (Sum acc) · Q2 whole-expression CountSketch+heap · shared input | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 54.020 vs 5.220 cost/s | -| P57 (L57) | Q1 exact (Sum acc, Rate acc) · Q2 exact · shared input | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.520 vs 5.220 cost/s | -| P58 (L58) | Q1 exact (Sum acc, Rate acc) · Q2 exact (Sum acc) · shared input | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | **selected** | cheapest valid (5.220 cost/s) | -| P59 (L59) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap · shared input | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P60 (L60) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap (Sum acc) · shared input | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P61 (L61) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap · shared input | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 16.720 vs 5.220 cost/s | -| P62 (L62) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap (Sum acc) · shared input | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.420 vs 5.220 cost/s | -| P63 (L63) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CMS+heap · shared input | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | invalid | q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative | -| P64 (L64) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CountSketch+heap · shared input | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 53.720 vs 5.220 cost/s | - -Count-Min + heap stays invalid, whole-expression or not: Q2 ranks -`sum_over_time` of raw samples, and nothing in the workload declares -`http_requests_total` non-negative (no metric type), so neither existing proof -(`UnitCount`, `ResetAwareCounterDerivative`) applies. CountSketch admits signed -weights. +| P1 (L1) | Q1 exact · Q2 exact | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.640 vs 4.620 cost/s | +| P2 (L2) | Q1 exact · Q2 exact (Sum acc) | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 8.340 vs 4.620 cost/s | +| P3 (L3) | Q1 exact · Q2 CMS+heap | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | separate | valid, costlier | 8.040 vs 4.620 cost/s | +| P4 (L4) | Q1 exact · Q2 CMS+heap (Sum acc) | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | valid, costlier | 7.740 vs 4.620 cost/s | +| P5 (L5) | Q1 exact · Q2 CountSketch+heap | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.840 vs 4.620 cost/s | +| P6 (L6) | Q1 exact · Q2 CountSketch+heap (Sum acc) | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.540 vs 4.620 cost/s | +| P7 (L7) | Q1 exact · Q2 whole-expression CMS+heap | rate: raw; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | valid, costlier | 9.640 vs 4.620 cost/s | +| P8 (L8) | Q1 exact · Q2 whole-expression CountSketch+heap | rate: raw; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.840 vs 4.620 cost/s | +| P9 (L9) | Q1 exact (Rate acc) · Q2 exact | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.340 vs 4.620 cost/s | +| P10 (L10) | Q1 exact (Rate acc) · Q2 exact (Sum acc) | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 8.040 vs 4.620 cost/s | +| P11 (L11) | Q1 exact (Rate acc) · Q2 CMS+heap | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | separate | valid, costlier | 7.740 vs 4.620 cost/s | +| P12 (L12) | Q1 exact (Rate acc) · Q2 CMS+heap (Sum acc) | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | valid, costlier | 7.440 vs 4.620 cost/s | +| P13 (L13) | Q1 exact (Rate acc) · Q2 CountSketch+heap | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.540 vs 4.620 cost/s | +| P14 (L14) | Q1 exact (Rate acc) · Q2 CountSketch+heap (Sum acc) | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.240 vs 4.620 cost/s | +| P15 (L15) | Q1 exact (Rate acc) · Q2 whole-expression CMS+heap | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | valid, costlier | 9.340 vs 4.620 cost/s | +| P16 (L16) | Q1 exact (Rate acc) · Q2 whole-expression CountSketch+heap | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.540 vs 4.620 cost/s | +| P17 (L17) | Q1 exact (Sum acc) · Q2 exact | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.540 vs 4.620 cost/s | +| P18 (L18) | Q1 exact (Sum acc) · Q2 exact (Sum acc) | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 8.240 vs 4.620 cost/s | +| P19 (L19) | Q1 exact (Sum acc) · Q2 CMS+heap | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | separate | valid, costlier | 7.940 vs 4.620 cost/s | +| P20 (L20) | Q1 exact (Sum acc) · Q2 CMS+heap (Sum acc) | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | valid, costlier | 7.640 vs 4.620 cost/s | +| P21 (L21) | Q1 exact (Sum acc) · Q2 CountSketch+heap | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.740 vs 4.620 cost/s | +| P22 (L22) | Q1 exact (Sum acc) · Q2 CountSketch+heap (Sum acc) | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.440 vs 4.620 cost/s | +| P23 (L23) | Q1 exact (Sum acc) · Q2 whole-expression CMS+heap | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | valid, costlier | 9.540 vs 4.620 cost/s | +| P24 (L24) | Q1 exact (Sum acc) · Q2 whole-expression CountSketch+heap | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.740 vs 4.620 cost/s | +| P25 (L25) | Q1 exact (Sum acc, Rate acc) · Q2 exact | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | separate | valid, costlier | 8.240 vs 4.620 cost/s | +| P26 (L26) | Q1 exact (Sum acc, Rate acc) · Q2 exact (Sum acc) | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | separate | valid, costlier | 7.940 vs 4.620 cost/s | +| P27 (L27) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | separate | valid, costlier | 7.640 vs 4.620 cost/s | +| P28 (L28) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap (Sum acc) | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | separate | valid, costlier | 7.340 vs 4.620 cost/s | +| P29 (L29) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | separate | valid, costlier | 19.440 vs 4.620 cost/s | +| P30 (L30) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap (Sum acc) | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | separate | valid, costlier | 19.140 vs 4.620 cost/s | +| P31 (L31) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CMS+heap | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | separate | valid, costlier | 9.240 vs 4.620 cost/s | +| P32 (L32) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CountSketch+heap | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | separate | valid, costlier | 56.440 vs 4.620 cost/s | +| P33 (L33) | Q1 exact · Q2 exact · shared input | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.920 vs 4.620 cost/s | +| P34 (L34) | Q1 exact · Q2 exact (Sum acc) · shared input | rate: raw; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | valid, costlier | 5.620 vs 4.620 cost/s | +| P35 (L35) | Q1 exact · Q2 CMS+heap · shared input | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | shared | valid, costlier | 5.320 vs 4.620 cost/s | +| P36 (L36) | Q1 exact · Q2 CMS+heap (Sum acc) · shared input | rate: raw; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | valid, costlier | 5.020 vs 4.620 cost/s | +| P37 (L37) | Q1 exact · Q2 CountSketch+heap · shared input | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 17.120 vs 4.620 cost/s | +| P38 (L38) | Q1 exact · Q2 CountSketch+heap (Sum acc) · shared input | rate: raw; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.820 vs 4.620 cost/s | +| P39 (L39) | Q1 exact · Q2 whole-expression CMS+heap · shared input | rate: raw; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | valid, costlier | 6.920 vs 4.620 cost/s | +| P40 (L40) | Q1 exact · Q2 whole-expression CountSketch+heap · shared input | rate: raw; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 54.120 vs 4.620 cost/s | +| P41 (L41) | Q1 exact (Rate acc) · Q2 exact · shared input | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.620 vs 4.620 cost/s | +| P42 (L42) | Q1 exact (Rate acc) · Q2 exact (Sum acc) · shared input | rate: Rate acc; sum: raw | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | valid, costlier | 5.320 vs 4.620 cost/s | +| P43 (L43) | Q1 exact (Rate acc) · Q2 CMS+heap · shared input | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: raw | shared | valid, costlier | 5.020 vs 4.620 cost/s | +| P44 (L44) | Q1 exact (Rate acc) · Q2 CMS+heap (Sum acc) · shared input | rate: Rate acc; sum: raw | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | valid, costlier | 4.720 vs 4.620 cost/s | +| P45 (L45) | Q1 exact (Rate acc) · Q2 CountSketch+heap · shared input | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 16.820 vs 4.620 cost/s | +| P46 (L46) | Q1 exact (Rate acc) · Q2 CountSketch+heap (Sum acc) · shared input | rate: Rate acc; sum: raw | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.520 vs 4.620 cost/s | +| P47 (L47) | Q1 exact (Rate acc) · Q2 whole-expression CMS+heap · shared input | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | valid, costlier | 6.620 vs 4.620 cost/s | +| P48 (L48) | Q1 exact (Rate acc) · Q2 whole-expression CountSketch+heap · shared input | rate: Rate acc; sum: raw | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 53.820 vs 4.620 cost/s | +| P49 (L49) | Q1 exact (Sum acc) · Q2 exact · shared input | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.820 vs 4.620 cost/s | +| P50 (L50) | Q1 exact (Sum acc) · Q2 exact (Sum acc) · shared input | rate: raw; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | valid, costlier | 5.520 vs 4.620 cost/s | +| P51 (L51) | Q1 exact (Sum acc) · Q2 CMS+heap · shared input | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | shared | valid, costlier | 5.220 vs 4.620 cost/s | +| P52 (L52) | Q1 exact (Sum acc) · Q2 CMS+heap (Sum acc) · shared input | rate: raw; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | valid, costlier | 4.920 vs 4.620 cost/s | +| P53 (L53) | Q1 exact (Sum acc) · Q2 CountSketch+heap · shared input | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 17.020 vs 4.620 cost/s | +| P54 (L54) | Q1 exact (Sum acc) · Q2 CountSketch+heap (Sum acc) · shared input | rate: raw; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.720 vs 4.620 cost/s | +| P55 (L55) | Q1 exact (Sum acc) · Q2 whole-expression CMS+heap · shared input | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | valid, costlier | 6.820 vs 4.620 cost/s | +| P56 (L56) | Q1 exact (Sum acc) · Q2 whole-expression CountSketch+heap · shared input | rate: raw; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 54.020 vs 4.620 cost/s | +| P57 (L57) | Q1 exact (Sum acc, Rate acc) · Q2 exact · shared input | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: raw | shared | valid, costlier | 5.520 vs 4.620 cost/s | +| P58 (L58) | Q1 exact (Sum acc, Rate acc) · Q2 exact (Sum acc) · shared input | rate: Rate acc; sum: Sum acc | top-k: exact (sort → limit); sum_over_time: Sum acc | shared | valid, costlier | 5.220 vs 4.620 cost/s | +| P59 (L59) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap · shared input | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: raw | shared | valid, costlier | 4.920 vs 4.620 cost/s | +| P60 (L60) | Q1 exact (Sum acc, Rate acc) · Q2 CMS+heap (Sum acc) · shared input | rate: Rate acc; sum: Sum acc | top-k: Count-Min + heap; sum_over_time: Sum acc | shared | **selected** | cheapest valid (4.620 cost/s) | +| P61 (L61) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap · shared input | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: raw | shared | valid, costlier | 16.720 vs 4.620 cost/s | +| P62 (L62) | Q1 exact (Sum acc, Rate acc) · Q2 CountSketch+heap (Sum acc) · shared input | rate: Rate acc; sum: Sum acc | top-k: CountSketch + heap; sum_over_time: Sum acc | shared | valid, costlier | 16.420 vs 4.620 cost/s | +| P63 (L63) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CMS+heap · shared input | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression Count-Min + heap over raw samples | shared | valid, costlier | 6.520 vs 4.620 cost/s | +| P64 (L64) | Q1 exact (Sum acc, Rate acc) · Q2 whole-expression CountSketch+heap · shared input | rate: Rate acc; sum: Sum acc | top-k and sum_over_time: whole-expression CountSketch + heap over raw samples | shared | valid, costlier | 53.720 vs 4.620 cost/s | + +Count-Min + heap is valid, whole-expression or not: Q2 ranks raw samples of +`http_requests_total`, or their `sum_over_time`, and the workload declares the +metric a counter, so Pass 1 attaches the `CounterSamples` non-negativity +proof. The planner never infers this from the `_total` suffix: without the +declaration, or for a gauge, the 24 Count-Min + heap candidates are invalid. +CountSketch admits signed weights either way. ## Stage 3: 1 plan @@ -204,14 +209,19 @@ Invariants: Outcome with the built-in models, per evaluation (CPU-ms; Stage 3 reports these × 0.1 evaluations/s, as cost per second, see -[Stage 3 cost model](stage3-cost-model.md)): P58 (all exact, with exact -accumulators for Q1's rate and sum and Q2's sum_over_time, over the shared -input) at 52.201, or 5.220 per second, against 79.401 for the same choices -with separate inputs (P26). The scan (23.2) and range (4.0) are priced once -instead of twice. The cheapest whole-expression CountSketch + heap plan, P64, -costs 537.201: its sketch updates 4,000,000 raw samples × (depth 125 + 1 heap -update) = 504.0, against 19.001 for Q2's exact Sum accumulator (5.0) and sort -+ limit (14.001). The doc's other typical winners need +[Stage 3 cost model](stage3-cost-model.md)): P60 (Q1 exact with Rate and Sum +accumulators; Q2 Count-Min + heap over an exact `sum_over_time` accumulator; +shared input) at 46.201, or 4.620 per second, against 73.401 for the same +choices with separate inputs (P28). The scan (23.2) and range (4.0) are priced +once instead of twice. Q2 costs 13.001 there: the Sum accumulator (5.0), the +Count-Min sketch updating 1,000,000 per-series sums × depth 8 (8.0) and its +estimate (0.001). The all-exact P58 (52.201, Q2 19.001 with sort + limit), +selected before the declaration, now ranks 8th: the seven shared-input +Count-Min + heap plans over per-series sums cost 46.201–52.201 (P51 ties P58). +The whole-expression Count-Min + heap plans rank 17th–20th (P63 cheapest at +65.201: 4,000,000 raw samples × depth 8 = 32.0), and the cheapest +whole-expression CountSketch + heap plan, P64, still costs 537.201 (depth 125 ++ 1 heap update = 504.0). The doc's other typical winners need window forms or materialization and are out of MVP scope. ## Ambiguities and MVP deviations diff --git a/docs/design_docs/proposals/stage3-cost-model.md b/docs/design_docs/proposals/stage3-cost-model.md index 84030a6b3..e74c24996 100644 --- a/docs/design_docs/proposals/stage3-cost-model.md +++ b/docs/design_docs/proposals/stage3-cost-model.md @@ -165,7 +165,9 @@ ingested every 15 s (λ = 66 667 rows/s). Every node runs at query time, since Stage 2 does not choose ingestion time yet. Both roots have the same 10-s interval, so every node, shared or not, has `r = 0.1`/s. -P58, the selected plan (all exact, the input shared by both queries): +P60, the selected plan (Q1 exact; Q2 Count-Min + heap over an exact +`sum_over_time` accumulator, valid because `http_requests_total` is declared a +counter; the input shared by both queries): | Node | Reached by | Work per evaluation | Per evaluation | r (/s) | Per second | |---|---|---|---|---|---| @@ -177,15 +179,15 @@ P58, the selected plan (all exact, the input shared by both queries): | Finalize | Q1 | 100 accumulators | 0.0001 | 0.1 | 0.00001 | | Sum accumulator (`sum_over_time`) | Q2 | 4 000 000 rows into 1 000 000 states | 4.0 | 0.1 | 0.40 | | Finalize | Q2 | 1 000 000 accumulators | 1.0 | 0.1 | 0.10 | -| Sort by `job` | Q2 | 1 000 000 rows in 100 partitions | 14.0 | 0.1 | 1.40 | -| Limit 10 per `job` | Q2 | 1 000 rows | 0.001 | 0.1 | 0.0001 | -| **Total** | | | **52.201** | | **5.220** | +| Count-Min + heap by `job` | Q2 | 1 000 000 rows × depth 8 into 100 states | 8.0 | 0.1 | 0.80 | +| Top-10 estimate | Q2 | 1 000 rows from 100 states | 0.001 | 0.1 | 0.0001 | +| **Total** | | | **46.201** | | **4.620** | -The runner-up is P42 at 5.320 per second; the same choices with separate -inputs (P26) cost 7.940, because the scan and range are charged twice. +The runner-up is P44 at 4.720 per second; the same choices with separate +inputs (P28) cost 7.340, because the scan and range are charged twice. -Before per-second pricing, P58 cost 52.201 CPU-ms per workload evaluation. Now -it costs 52.201 × 0.1 = 5.220 per second. Every other candidate scales by the +Before per-second pricing, P60 cost 46.201 CPU-ms per workload evaluation. Now +it costs 46.201 × 0.1 = 4.620 per second. Every other candidate scales by the same factor, so the ranking is unchanged. With uniform recurrence and no ingestion-time nodes the new unit is a rescaling. It changes the ranking once recurrences differ, or once Stage 2 offers ingestion-time candidates that pay diff --git a/tools/dag-viewer/examples/planner-layering-example1.json b/tools/dag-viewer/examples/planner-layering-example1.json index 85740279e..0811c32f4 100644 --- a/tools/dag-viewer/examples/planner-layering-example1.json +++ b/tools/dag-viewer/examples/planner-layering-example1.json @@ -2442,7 +2442,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -3186,7 +3187,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -3865,7 +3867,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -4609,7 +4612,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -5220,7 +5224,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -5831,7 +5836,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -7985,7 +7991,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -8795,7 +8802,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -9540,7 +9548,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -10350,7 +10359,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -11027,7 +11037,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -11704,7 +11715,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -13804,7 +13816,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -14596,7 +14609,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -15323,7 +15337,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -16115,7 +16130,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -16774,7 +16790,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -17433,7 +17450,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -19731,7 +19749,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -20589,7 +20608,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -21382,7 +21402,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -22240,7 +22261,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -22965,7 +22987,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -23690,7 +23713,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -25148,7 +25172,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -25726,7 +25751,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -26239,7 +26265,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -26817,7 +26844,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -27262,7 +27290,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -27707,7 +27736,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -29363,7 +29393,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -30007,7 +30038,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -30586,7 +30618,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -31230,7 +31263,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -31741,7 +31775,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -32252,7 +32287,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -33854,7 +33890,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -34480,7 +34517,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -35041,7 +35079,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -35667,7 +35706,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -36160,7 +36200,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -36653,7 +36694,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -38453,7 +38495,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -39145,7 +39188,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -39772,7 +39816,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -40464,7 +40509,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -41023,7 +41069,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -41582,7 +41629,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -44998,7 +45046,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -46210,7 +46259,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -47296,7 +47346,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -48508,7 +48559,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -49468,7 +49520,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -50428,7 +50481,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -54177,7 +54231,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -55516,7 +55571,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -56729,7 +56785,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -58068,7 +58125,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -59155,7 +59213,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -60242,7 +60301,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -63886,7 +63946,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -65190,7 +65251,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -66368,7 +66430,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -67672,7 +67735,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -68724,7 +68788,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -69776,7 +69841,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -73801,7 +73867,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -75232,7 +75299,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -76537,7 +76605,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -77968,7 +78037,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -79147,7 +79217,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -80326,7 +80397,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -83013,7 +83085,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -83998,7 +84071,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -84857,7 +84931,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -85842,7 +85917,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -86575,7 +86651,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -87308,7 +87385,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -90376,7 +90454,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -91488,7 +91567,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -92474,7 +92554,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -93586,7 +93667,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -94446,7 +94528,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -95306,7 +95389,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -98269,7 +98353,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -99346,7 +99431,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -100297,7 +100383,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -101374,7 +101461,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -102199,7 +102287,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -103024,7 +103113,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -106368,7 +106458,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -107572,7 +107663,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -108650,7 +108742,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -109854,7 +109947,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -110806,7 +110900,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -111758,7 +111853,8 @@ "Column": "SampleValue" }, "weight_domain": { - "kind": "unknown_or_signed" + "kind": "non_negative", + "proof": "counter_samples" } }, "reduction": { @@ -111934,7 +112030,7 @@ "total": 8.0401, "unit": "cost_per_second" }, - "P13": { + "P11": { "per_node": { "0": { "cost": 2.32, @@ -111969,8 +112065,8 @@ "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" }, "8": { - "cost": 12.600000000000001, - "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" }, "9": { "cost": 0.0001, @@ -111978,10 +112074,10 @@ } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 19.540100000000002, + "total": 7.7401, "unit": "cost_per_second" }, - "P14": { + "P12": { "per_node": { "0": { "cost": 2.32, @@ -112024,15 +112120,15 @@ "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "9": { - "cost": 12.600000000000001, - "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 19.2401, + "total": 7.4401, "unit": "cost_per_second" }, - "P16": { + "P13": { "per_node": { "0": { "cost": 2.32, @@ -112063,19 +112159,23 @@ "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "7": { - "cost": 50.400000000000006, - "detail": "build CountSketchWithHeap into 100 states: 4000000 rows x depth 126; x 0.1000 evaluations/s" + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" }, "8": { + "cost": 12.600000000000001, + "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" + }, + "9": { "cost": 0.0001, "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 56.54010000000001, + "total": 19.540100000000002, "unit": "cost_per_second" }, - "P17": { + "P14": { "per_node": { "0": { "cost": 2.32, @@ -112085,17 +112185,21 @@ "cost": 0.4, "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, + "10": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + }, "2": { - "cost": 0.8, - "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" }, "3": { "cost": 0.1, - "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "4": { - "cost": 9.999999999999999e-6, - "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" }, "5": { "cost": 2.32, @@ -112106,23 +112210,23 @@ "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "7": { - "cost": 0.8, - "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" }, "8": { - "cost": 1.4000000000000001, - "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "9": { - "cost": 0.0001, - "detail": "limit to 1000 rows; x 0.1000 evaluations/s" + "cost": 12.600000000000001, + "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 8.540109999999999, + "total": 19.2401, "unit": "cost_per_second" }, - "P18": { + "P15": { "per_node": { "0": { "cost": 2.32, @@ -112132,21 +112236,17 @@ "cost": 0.4, "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, - "10": { - "cost": 0.0001, - "detail": "limit to 1000 rows; x 0.1000 evaluations/s" - }, "2": { - "cost": 0.8, - "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" }, "3": { "cost": 0.1, - "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "4": { - "cost": 9.999999999999999e-6, - "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" }, "5": { "cost": 2.32, @@ -112157,23 +112257,62 @@ "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "7": { - "cost": 0.4, - "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" }, "8": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 9.3401, + "unit": "cost_per_second" + }, + "P16": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { "cost": 0.1, "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, - "9": { - "cost": 1.4000000000000001, - "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" + "4": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "5": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "7": { + "cost": 50.400000000000006, + "detail": "build CountSketchWithHeap into 100 states: 4000000 rows x depth 126; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 8.24011, + "total": 56.54010000000001, "unit": "cost_per_second" }, - "P2": { + "P17": { "per_node": { "0": { "cost": 2.32, @@ -112188,24 +112327,24 @@ "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" }, "3": { - "cost": 0.2, - "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" }, "4": { - "cost": 2.32, - "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" }, "5": { - "cost": 0.4, - "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" }, "6": { "cost": 0.4, - "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "7": { - "cost": 0.1, - "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" }, "8": { "cost": 1.4000000000000001, @@ -112217,10 +112356,10 @@ } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 8.3401, + "total": 8.540109999999999, "unit": "cost_per_second" }, - "P21": { + "P18": { "per_node": { "0": { "cost": 2.32, @@ -112230,6 +112369,10 @@ "cost": 0.4, "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, + "10": { + "cost": 0.0001, + "detail": "limit to 1000 rows; x 0.1000 evaluations/s" + }, "2": { "cost": 0.8, "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" @@ -112251,23 +112394,23 @@ "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "7": { - "cost": 0.8, - "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" }, "8": { - "cost": 12.600000000000001, - "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "9": { - "cost": 0.0001, - "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + "cost": 1.4000000000000001, + "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 19.74011, + "total": 8.24011, "unit": "cost_per_second" }, - "P22": { + "P19": { "per_node": { "0": { "cost": 2.32, @@ -112277,10 +112420,202 @@ "cost": 0.4, "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, - "10": { - "cost": 0.0001, - "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" - }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "4": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "5": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 7.940109999999999, + "unit": "cost_per_second" + }, + "P2": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "4": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "8": { + "cost": 1.4000000000000001, + "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.0001, + "detail": "limit to 1000 rows; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 8.3401, + "unit": "cost_per_second" + }, + "P20": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "10": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "4": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "5": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 7.640109999999999, + "unit": "cost_per_second" + }, + "P21": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "4": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "5": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "8": { + "cost": 12.600000000000001, + "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 19.74011, + "unit": "cost_per_second" + }, + "P22": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "10": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + }, "2": { "cost": 0.8, "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" @@ -112318,6 +112653,49 @@ "total": 19.44011, "unit": "cost_per_second" }, + "P23": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "4": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "5": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "7": { + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 9.540109999999999, + "unit": "cost_per_second" + }, "P24": { "per_node": { "0": { @@ -112467,6 +112845,112 @@ "total": 7.940110000000001, "unit": "cost_per_second" }, + "P27": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "10": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "5": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "6": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 7.64011, + "unit": "cost_per_second" + }, + "P28": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "10": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "11": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "5": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "6": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 7.34011, + "unit": "cost_per_second" + }, "P29": { "per_node": { "0": { @@ -112518,6 +113002,49 @@ "total": 19.44011, "unit": "cost_per_second" }, + "P3": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "4": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 8.040099999999999, + "unit": "cost_per_second" + }, "P30": { "per_node": { "0": { @@ -112573,6 +113100,53 @@ "total": 19.140110000000004, "unit": "cost_per_second" }, + "P31": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "5": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "6": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "8": { + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 9.240110000000001, + "unit": "cost_per_second" + }, "P32": { "per_node": { "0": { @@ -112694,6 +113268,80 @@ "total": 5.6201, "unit": "cost_per_second" }, + "P35": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 5.320099999999999, + "unit": "cost_per_second" + }, + "P36": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 5.020099999999999, + "unit": "cost_per_second" + }, "P37": { "per_node": { "0": { @@ -112768,6 +113416,84 @@ "total": 16.8201, "unit": "cost_per_second" }, + "P39": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "4": { + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 6.9201, + "unit": "cost_per_second" + }, + "P4": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "4": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 7.740099999999999, + "unit": "cost_per_second" + }, "P40": { "per_node": { "0": { @@ -112881,6 +113607,88 @@ "total": 5.3201, "unit": "cost_per_second" }, + "P43": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 5.020099999999999, + "unit": "cost_per_second" + }, + "P44": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 4.7200999999999995, + "unit": "cost_per_second" + }, "P45": { "per_node": { "0": { @@ -112963,6 +113771,41 @@ "total": 16.520100000000003, "unit": "cost_per_second" }, + "P47": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "5": { + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 6.6201, + "unit": "cost_per_second" + }, "P48": { "per_node": { "0": { @@ -113123,6 +113966,88 @@ "total": 5.52011, "unit": "cost_per_second" }, + "P51": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "4": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 5.220109999999999, + "unit": "cost_per_second" + }, + "P52": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "4": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 4.920109999999999, + "unit": "cost_per_second" + }, "P53": { "per_node": { "0": { @@ -113205,6 +114130,41 @@ "total": 16.720110000000002, "unit": "cost_per_second" }, + "P55": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "4": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "5": { + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 6.82011, + "unit": "cost_per_second" + }, "P56": { "per_node": { "0": { @@ -113271,19 +114231,109 @@ "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" }, "7": { - "cost": 1.4000000000000001, - "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" + "cost": 1.4000000000000001, + "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" + }, + "8": { + "cost": 0.0001, + "detail": "limit to 1000 rows; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 5.52011, + "unit": "cost_per_second" + }, + "P58": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "5": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.4, + "detail": "build exact Sum accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "8": { + "cost": 1.4000000000000001, + "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" + }, + "9": { + "cost": 0.0001, + "detail": "limit to 1000 rows; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 5.22011, + "unit": "cost_per_second" + }, + "P59": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "5": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "6": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" }, "8": { "cost": 0.0001, - "detail": "limit to 1000 rows; x 0.1000 evaluations/s" + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 5.52011, + "total": 4.920109999999999, "unit": "cost_per_second" }, - "P58": { + "P6": { "per_node": { "0": { "cost": 2.32, @@ -113294,20 +114344,20 @@ "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "2": { - "cost": 0.4, - "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" }, "3": { - "cost": 0.1, - "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" }, "4": { - "cost": 0.1, - "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" }, "5": { - "cost": 9.999999999999999e-6, - "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "6": { "cost": 0.4, @@ -113318,19 +114368,19 @@ "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "8": { - "cost": 1.4000000000000001, - "detail": "sort 1000000 rows in 100 partitions; x 0.1000 evaluations/s" + "cost": 12.600000000000001, + "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" }, "9": { "cost": 0.0001, - "detail": "limit to 1000 rows; x 0.1000 evaluations/s" + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 5.22011, + "total": 19.5401, "unit": "cost_per_second" }, - "P6": { + "P60": { "per_node": { "0": { "cost": 2.32, @@ -113341,20 +114391,20 @@ "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" }, "2": { - "cost": 0.8, - "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" }, "3": { - "cost": 0.2, - "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "4": { - "cost": 2.32, - "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" }, "5": { - "cost": 0.4, - "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" }, "6": { "cost": 0.4, @@ -113365,8 +114415,8 @@ "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" }, "8": { - "cost": 12.600000000000001, - "detail": "build CountSketchWithHeap into 100 states: 1000000 rows x depth 126; x 0.1000 evaluations/s" + "cost": 0.8, + "detail": "build CmsWithHeap into 100 states: 1000000 rows x depth 8; x 0.1000 evaluations/s" }, "9": { "cost": 0.0001, @@ -113374,7 +114424,7 @@ } }, "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", - "total": 19.5401, + "total": 4.6201099999999995, "unit": "cost_per_second" }, "P61": { @@ -113467,6 +114517,45 @@ "total": 16.42011, "unit": "cost_per_second" }, + "P63": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.4, + "detail": "build exact Rate accumulator into 1000000 states: 4000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.1, + "detail": "finalize 1000000 accumulators; x 0.1000 evaluations/s" + }, + "4": { + "cost": 0.1, + "detail": "build exact Sum accumulator into 100 states: 1000000 rows x depth 1; x 0.1000 evaluations/s" + }, + "5": { + "cost": 9.999999999999999e-6, + "detail": "finalize 100 accumulators; x 0.1000 evaluations/s" + }, + "6": { + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 6.52011, + "unit": "cost_per_second" + }, "P64": { "per_node": { "0": { @@ -113506,6 +114595,45 @@ "total": 53.720110000000005, "unit": "cost_per_second" }, + "P7": { + "per_node": { + "0": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "1": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "2": { + "cost": 0.8, + "detail": "hash aggregate 4000000 rows into 1000000 groups; x 0.1000 evaluations/s" + }, + "3": { + "cost": 0.2, + "detail": "hash aggregate 1000000 rows into 100 groups; x 0.1000 evaluations/s" + }, + "4": { + "cost": 2.32, + "detail": "scan 4000000 samples; x 0.1000 evaluations/s" + }, + "5": { + "cost": 0.4, + "detail": "time range 60s: pass 4000000 rows; x 0.1000 evaluations/s" + }, + "6": { + "cost": 3.2, + "detail": "build CmsWithHeap into 100 states: 4000000 rows x depth 8; x 0.1000 evaluations/s" + }, + "7": { + "cost": 0.0001, + "detail": "estimate 1000 rows from 100 states; x 0.1000 evaluations/s" + } + }, + "source": "analytical-cost-v2 (illustrative statistics, calibration illustrative-v2)", + "total": 9.6401, + "unit": "cost_per_second" + }, "P8": { "per_node": { "0": { @@ -113595,322 +114723,322 @@ }, "rejected": [ { - "id": "P3", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false - }, - { - "id": "P4", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P1", + "reason": "costlier: 8.640 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P7", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P2", + "reason": "costlier: 8.340 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P11", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P3", + "reason": "costlier: 8.040 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P12", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P4", + "reason": "costlier: 7.740 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P15", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P5", + "reason": "costlier: 19.840 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P19", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P6", + "reason": "costlier: 19.540 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P20", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P7", + "reason": "costlier: 9.640 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P23", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P8", + "reason": "costlier: 56.840 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P27", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P9", + "reason": "costlier: 8.340 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P28", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P10", + "reason": "costlier: 8.040 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P31", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P11", + "reason": "costlier: 7.740 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P35", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P12", + "reason": "costlier: 7.440 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P36", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P13", + "reason": "costlier: 19.540 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P39", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P14", + "reason": "costlier: 19.240 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P43", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P15", + "reason": "costlier: 9.340 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P44", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P16", + "reason": "costlier: 56.540 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P47", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P17", + "reason": "costlier: 8.540 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P51", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P18", + "reason": "costlier: 8.240 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P52", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P19", + "reason": "costlier: 7.940 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P55", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P20", + "reason": "costlier: 7.640 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P59", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P21", + "reason": "costlier: 19.740 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P60", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P22", + "reason": "costlier: 19.440 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P63", - "reason": "q2: CmsWithHeap needs non-negative update weights, and these are not proven non-negative", - "valid": false + "id": "P23", + "reason": "costlier: 9.540 vs 4.620 cost_per_second", + "valid": true }, { - "id": "P1", - "reason": "costlier: 8.640 vs 5.220 cost_per_second", + "id": "P24", + "reason": "costlier: 56.740 vs 4.620 cost_per_second", "valid": true }, { - "id": "P2", - "reason": "costlier: 8.340 vs 5.220 cost_per_second", + "id": "P25", + "reason": "costlier: 8.240 vs 4.620 cost_per_second", "valid": true }, { - "id": "P5", - "reason": "costlier: 19.840 vs 5.220 cost_per_second", + "id": "P26", + "reason": "costlier: 7.940 vs 4.620 cost_per_second", "valid": true }, { - "id": "P6", - "reason": "costlier: 19.540 vs 5.220 cost_per_second", + "id": "P27", + "reason": "costlier: 7.640 vs 4.620 cost_per_second", "valid": true }, { - "id": "P8", - "reason": "costlier: 56.840 vs 5.220 cost_per_second", + "id": "P28", + "reason": "costlier: 7.340 vs 4.620 cost_per_second", "valid": true }, { - "id": "P9", - "reason": "costlier: 8.340 vs 5.220 cost_per_second", + "id": "P29", + "reason": "costlier: 19.440 vs 4.620 cost_per_second", "valid": true }, { - "id": "P10", - "reason": "costlier: 8.040 vs 5.220 cost_per_second", + "id": "P30", + "reason": "costlier: 19.140 vs 4.620 cost_per_second", "valid": true }, { - "id": "P13", - "reason": "costlier: 19.540 vs 5.220 cost_per_second", + "id": "P31", + "reason": "costlier: 9.240 vs 4.620 cost_per_second", "valid": true }, { - "id": "P14", - "reason": "costlier: 19.240 vs 5.220 cost_per_second", + "id": "P32", + "reason": "costlier: 56.440 vs 4.620 cost_per_second", "valid": true }, { - "id": "P16", - "reason": "costlier: 56.540 vs 5.220 cost_per_second", + "id": "P33", + "reason": "costlier: 5.920 vs 4.620 cost_per_second", "valid": true }, { - "id": "P17", - "reason": "costlier: 8.540 vs 5.220 cost_per_second", + "id": "P34", + "reason": "costlier: 5.620 vs 4.620 cost_per_second", "valid": true }, { - "id": "P18", - "reason": "costlier: 8.240 vs 5.220 cost_per_second", + "id": "P35", + "reason": "costlier: 5.320 vs 4.620 cost_per_second", "valid": true }, { - "id": "P21", - "reason": "costlier: 19.740 vs 5.220 cost_per_second", + "id": "P36", + "reason": "costlier: 5.020 vs 4.620 cost_per_second", "valid": true }, { - "id": "P22", - "reason": "costlier: 19.440 vs 5.220 cost_per_second", + "id": "P37", + "reason": "costlier: 17.120 vs 4.620 cost_per_second", "valid": true }, { - "id": "P24", - "reason": "costlier: 56.740 vs 5.220 cost_per_second", + "id": "P38", + "reason": "costlier: 16.820 vs 4.620 cost_per_second", "valid": true }, { - "id": "P25", - "reason": "costlier: 8.240 vs 5.220 cost_per_second", + "id": "P39", + "reason": "costlier: 6.920 vs 4.620 cost_per_second", "valid": true }, { - "id": "P26", - "reason": "costlier: 7.940 vs 5.220 cost_per_second", + "id": "P40", + "reason": "costlier: 54.120 vs 4.620 cost_per_second", "valid": true }, { - "id": "P29", - "reason": "costlier: 19.440 vs 5.220 cost_per_second", + "id": "P41", + "reason": "costlier: 5.620 vs 4.620 cost_per_second", "valid": true }, { - "id": "P30", - "reason": "costlier: 19.140 vs 5.220 cost_per_second", + "id": "P42", + "reason": "costlier: 5.320 vs 4.620 cost_per_second", "valid": true }, { - "id": "P32", - "reason": "costlier: 56.440 vs 5.220 cost_per_second", + "id": "P43", + "reason": "costlier: 5.020 vs 4.620 cost_per_second", "valid": true }, { - "id": "P33", - "reason": "costlier: 5.920 vs 5.220 cost_per_second", + "id": "P44", + "reason": "costlier: 4.720 vs 4.620 cost_per_second", "valid": true }, { - "id": "P34", - "reason": "costlier: 5.620 vs 5.220 cost_per_second", + "id": "P45", + "reason": "costlier: 16.820 vs 4.620 cost_per_second", "valid": true }, { - "id": "P37", - "reason": "costlier: 17.120 vs 5.220 cost_per_second", + "id": "P46", + "reason": "costlier: 16.520 vs 4.620 cost_per_second", "valid": true }, { - "id": "P38", - "reason": "costlier: 16.820 vs 5.220 cost_per_second", + "id": "P47", + "reason": "costlier: 6.620 vs 4.620 cost_per_second", "valid": true }, { - "id": "P40", - "reason": "costlier: 54.120 vs 5.220 cost_per_second", + "id": "P48", + "reason": "costlier: 53.820 vs 4.620 cost_per_second", "valid": true }, { - "id": "P41", - "reason": "costlier: 5.620 vs 5.220 cost_per_second", + "id": "P49", + "reason": "costlier: 5.820 vs 4.620 cost_per_second", "valid": true }, { - "id": "P42", - "reason": "costlier: 5.320 vs 5.220 cost_per_second", + "id": "P50", + "reason": "costlier: 5.520 vs 4.620 cost_per_second", "valid": true }, { - "id": "P45", - "reason": "costlier: 16.820 vs 5.220 cost_per_second", + "id": "P51", + "reason": "costlier: 5.220 vs 4.620 cost_per_second", "valid": true }, { - "id": "P46", - "reason": "costlier: 16.520 vs 5.220 cost_per_second", + "id": "P52", + "reason": "costlier: 4.920 vs 4.620 cost_per_second", "valid": true }, { - "id": "P48", - "reason": "costlier: 53.820 vs 5.220 cost_per_second", + "id": "P53", + "reason": "costlier: 17.020 vs 4.620 cost_per_second", "valid": true }, { - "id": "P49", - "reason": "costlier: 5.820 vs 5.220 cost_per_second", + "id": "P54", + "reason": "costlier: 16.720 vs 4.620 cost_per_second", "valid": true }, { - "id": "P50", - "reason": "costlier: 5.520 vs 5.220 cost_per_second", + "id": "P55", + "reason": "costlier: 6.820 vs 4.620 cost_per_second", "valid": true }, { - "id": "P53", - "reason": "costlier: 17.020 vs 5.220 cost_per_second", + "id": "P56", + "reason": "costlier: 54.020 vs 4.620 cost_per_second", "valid": true }, { - "id": "P54", - "reason": "costlier: 16.720 vs 5.220 cost_per_second", + "id": "P57", + "reason": "costlier: 5.520 vs 4.620 cost_per_second", "valid": true }, { - "id": "P56", - "reason": "costlier: 54.020 vs 5.220 cost_per_second", + "id": "P58", + "reason": "costlier: 5.220 vs 4.620 cost_per_second", "valid": true }, { - "id": "P57", - "reason": "costlier: 5.520 vs 5.220 cost_per_second", + "id": "P59", + "reason": "costlier: 4.920 vs 4.620 cost_per_second", "valid": true }, { "id": "P61", - "reason": "costlier: 16.720 vs 5.220 cost_per_second", + "reason": "costlier: 16.720 vs 4.620 cost_per_second", "valid": true }, { "id": "P62", - "reason": "costlier: 16.420 vs 5.220 cost_per_second", + "reason": "costlier: 16.420 vs 4.620 cost_per_second", + "valid": true + }, + { + "id": "P63", + "reason": "costlier: 6.520 vs 4.620 cost_per_second", "valid": true }, { "id": "P64", - "reason": "costlier: 53.720 vs 5.220 cost_per_second", + "reason": "costlier: 53.720 vs 4.620 cost_per_second", "valid": true } ], - "selected": "P58" + "selected": "P60" }, "workload": { "queries": [