diff --git a/src/query/service/tests/it/sql/planner/optimizer/agg_index_query_rewrite.rs b/src/query/service/tests/it/sql/planner/optimizer/agg_index_query_rewrite.rs index b30240cc7ad9..989911ae584b 100644 --- a/src/query/service/tests/it/sql/planner/optimizer/agg_index_query_rewrite.rs +++ b/src/query/service/tests/it/sql/planner/optimizer/agg_index_query_rewrite.rs @@ -27,9 +27,9 @@ use databend_common_expression::TableDataType; use databend_common_expression::TableField; use databend_common_expression::TableSchemaRefExt; use databend_common_meta_app::schema::CreateOption; -use databend_common_sql::optimizer::agg_index; use databend_common_sql::optimizer::OptimizerContext; use databend_common_sql::optimizer::RecursiveOptimizer; +use databend_common_sql::optimizer::RuleID; use databend_common_sql::optimizer::SExpr; use databend_common_sql::optimizer::DEFAULT_REWRITE_RULES; use databend_common_sql::plans::AggIndexInfo; @@ -516,28 +516,32 @@ async fn test_query_rewrite_impl(format: &str) -> Result<()> { let _ = interpreter.execute(ctx.clone()).await?; let test_suites = get_test_suites(); - for suite in test_suites { - let (query, _, metadata) = plan_sql(ctx.clone(), suite.query, true).await?; + for suite in test_suites.into_iter() { let (index, _, _) = plan_sql(ctx.clone(), suite.index, false).await?; - let meta = metadata.read(); - let base_columns = meta.columns_by_table_index(0); - let result = agg_index::try_rewrite(0, "t", &base_columns, &query, &[( - 0, - suite.index.to_string(), - index, - )])?; + let (mut query, _, metadata) = plan_sql(ctx.clone(), suite.query, true).await?; + { + let mut metadata = metadata.write(); + metadata.add_agg_indexes("default.default.t".to_string(), vec![( + 0, + suite.index.to_string(), + index, + )]); + } + query.clear_applied_rules(); + let result = RecursiveOptimizer::new( + &[RuleID::TryApplyAggIndex], + &OptimizerContext::new(ctx.clone(), metadata.clone()), + ) + .run(&query)?; + let agg_index = find_push_down_index_info(&result)?; assert_eq!( suite.is_matched, - result.is_some(), + agg_index.is_some(), "query: {}, index: {}", suite.query, suite.index ); - if let Some(result) = result { - let agg_index = find_push_down_index_info(&result)?; - assert!(agg_index.is_some()); - let agg_index = agg_index.as_ref().unwrap(); - + if let Some(agg_index) = agg_index { let selection = format_selection(agg_index); assert_eq!( suite.index_selection, selection, diff --git a/src/query/sql/src/planner/binder/bind_query/bind_select.rs b/src/query/sql/src/planner/binder/bind_query/bind_select.rs index 3edebaf36b8f..4fd37192b828 100644 --- a/src/query/sql/src/planner/binder/bind_query/bind_select.rs +++ b/src/query/sql/src/planner/binder/bind_query/bind_select.rs @@ -213,18 +213,12 @@ impl Binder { )?; } + s_expr = self.bind_projection(&mut from_context, &projections, &scalar_items, s_expr)?; + if !order_by.is_empty() { - s_expr = self.bind_order_by( - &from_context, - order_items, - &select_list, - &mut scalar_items, - s_expr, - )?; + s_expr = self.bind_order_by(&from_context, order_items, &select_list, s_expr)?; } - s_expr = self.bind_projection(&mut from_context, &projections, &scalar_items, s_expr)?; - if from_context.have_async_func { // rewrite async function to async function plan let mut async_func_rewriter = AsyncFunctionRewriter::new(self.metadata.clone()); diff --git a/src/query/sql/src/planner/binder/ddl/index.rs b/src/query/sql/src/planner/binder/ddl/index.rs index fb5565f5d80c..5c5c8c0576de 100644 --- a/src/query/sql/src/planner/binder/ddl/index.rs +++ b/src/query/sql/src/planner/binder/ddl/index.rs @@ -365,7 +365,8 @@ impl Binder { bind_context.planning_agg_index = true; let plan = if let Statement::Query(_) = &stmt { let select_plan = self.bind_statement(bind_context, &stmt).await?; - let opt_ctx = OptimizerContext::new(self.ctx.clone(), self.metadata.clone()); + let opt_ctx = OptimizerContext::new(self.ctx.clone(), self.metadata.clone()) + .with_planning_agg_index(); Ok(optimize(opt_ctx, select_plan).await?) } else { Err(ErrorCode::UnsupportedIndex("statement is not query")) diff --git a/src/query/sql/src/planner/binder/sort.rs b/src/query/sql/src/planner/binder/sort.rs index a11426492c08..8cf97a809cb9 100644 --- a/src/query/sql/src/planner/binder/sort.rs +++ b/src/query/sql/src/planner/binder/sort.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::hash_map::Entry; use std::collections::HashMap; use std::sync::Arc; @@ -33,7 +32,6 @@ use crate::optimizer::SExpr; use crate::planner::semantic::GroupingChecker; use crate::plans::BoundColumnRef; use crate::plans::CastExpr; -use crate::plans::EvalScalar; use crate::plans::FunctionCall; use crate::plans::LambdaFunc; use crate::plans::ScalarExpr; @@ -44,7 +42,6 @@ use crate::plans::UDFCall; use crate::plans::VisitorMut as _; use crate::BindContext; use crate::IndexType; -use crate::WindowChecker; #[derive(Debug)] pub struct OrderItems { @@ -186,12 +183,9 @@ impl Binder { from_context: &BindContext, order_by: OrderItems, select_list: &SelectList<'_>, - scalar_items: &mut HashMap, child: SExpr, ) -> Result { let mut order_by_items = Vec::with_capacity(order_by.items.len()); - let mut scalars = vec![]; - for order in order_by.items { if from_context.in_grouping { let mut group_checker = GroupingChecker::new(from_context); @@ -206,23 +200,6 @@ impl Binder { } } - if let Entry::Occupied(entry) = scalar_items.entry(order.index) { - let need_eval = !matches!(entry.get().scalar, ScalarExpr::BoundColumnRef(_)); - if need_eval { - // Remove the entry to avoid bind again in later process (bind_projection). - let (index, item) = entry.remove_entry(); - let mut scalar = item.scalar; - if from_context.in_grouping { - let mut group_checker = GroupingChecker::new(from_context); - group_checker.visit(&mut scalar)?; - } else if !from_context.windows.window_functions.is_empty() { - let mut window_checker = WindowChecker::new(from_context); - window_checker.visit(&mut scalar)?; - } - scalars.push(ScalarItem { scalar, index }); - } - } - let order_by_item = SortItem { index: order.index, asc: order.asc, @@ -232,13 +209,6 @@ impl Binder { order_by_items.push(order_by_item); } - let mut new_expr = if !scalars.is_empty() { - let eval_scalar = EvalScalar { items: scalars }; - SExpr::create_unary(Arc::new(eval_scalar.into()), Arc::new(child)) - } else { - child - }; - let sort_plan = Sort { items: order_by_items, limit: None, @@ -246,7 +216,7 @@ impl Binder { pre_projection: None, window_partition: vec![], }; - new_expr = SExpr::create_unary(Arc::new(sort_plan.into()), Arc::new(new_expr)); + let new_expr = SExpr::create_unary(Arc::new(sort_plan.into()), Arc::new(child)); Ok(new_expr) } diff --git a/src/query/sql/src/planner/dataframe.rs b/src/query/sql/src/planner/dataframe.rs index 46be4095423d..97681ee9cb14 100644 --- a/src/query/sql/src/planner/dataframe.rs +++ b/src/query/sql/src/planner/dataframe.rs @@ -406,7 +406,6 @@ impl Dataframe { &self.bind_context, order_items, &select_list, - &mut scalar_items, self.s_expr, )?; diff --git a/src/query/sql/src/planner/metadata.rs b/src/query/sql/src/planner/metadata.rs index ad1a2e5fa82d..6bd121374f96 100644 --- a/src/query/sql/src/planner/metadata.rs +++ b/src/query/sql/src/planner/metadata.rs @@ -325,6 +325,10 @@ impl Metadata { self.agg_indexes.get(table).map(|v| v.as_slice()) } + pub fn has_agg_indexes(&self) -> bool { + !self.agg_indexes.is_empty() + } + #[allow(clippy::too_many_arguments)] pub fn add_table( &mut self, diff --git a/src/query/sql/src/planner/optimizer/optimizer.rs b/src/query/sql/src/planner/optimizer/optimizer.rs index 461a267b509c..625ce0bd0dd2 100644 --- a/src/query/sql/src/planner/optimizer/optimizer.rs +++ b/src/query/sql/src/planner/optimizer/optimizer.rs @@ -67,6 +67,7 @@ pub struct OptimizerContext { enable_distributed_optimization: bool, enable_join_reorder: bool, enable_dphyp: bool, + planning_agg_index: bool, #[educe(Debug(ignore))] sample_executor: Option>, } @@ -81,6 +82,7 @@ impl OptimizerContext { enable_join_reorder: true, enable_dphyp: true, sample_executor: None, + planning_agg_index: false, } } @@ -106,6 +108,11 @@ impl OptimizerContext { self.sample_executor = sample_executor; self } + + pub fn with_planning_agg_index(mut self) -> Self { + self.planning_agg_index = true; + self + } } /// A recursive optimizer that will apply the given rules recursively. @@ -410,8 +417,10 @@ pub async fn optimize_query(opt_ctx: &mut OptimizerContext, mut s_expr: SExpr) - } }; - s_expr = - RecursiveOptimizer::new([RuleID::EliminateEvalScalar].as_slice(), opt_ctx).run(&s_expr)?; + if !opt_ctx.planning_agg_index { + s_expr = RecursiveOptimizer::new([RuleID::EliminateEvalScalar].as_slice(), opt_ctx) + .run(&s_expr)?; + } Ok(s_expr) } diff --git a/src/query/sql/src/planner/optimizer/rule/factory.rs b/src/query/sql/src/planner/optimizer/rule/factory.rs index 2a51d73c96f3..e3b322b39e17 100644 --- a/src/query/sql/src/planner/optimizer/rule/factory.rs +++ b/src/query/sql/src/planner/optimizer/rule/factory.rs @@ -25,6 +25,7 @@ use super::rewrite::RulePushDownFilterWindow; use super::rewrite::RulePushDownLimitAggregate; use super::rewrite::RulePushDownLimitEvalScalar; use super::rewrite::RulePushDownPrewhere; +use super::rewrite::RulePushDownSortEvalScalar; use super::rewrite::RuleTryApplyAggIndex; use crate::optimizer::rule::rewrite::RuleEliminateFilter; use crate::optimizer::rule::rewrite::RuleEliminateSort; @@ -57,7 +58,7 @@ pub const MAX_PUSH_DOWN_LIMIT: usize = 10000; impl RuleFactory { pub fn create_rule(id: RuleID, metadata: MetadataRef) -> Result { match id { - RuleID::EliminateEvalScalar => Ok(Box::new(RuleEliminateEvalScalar::new())), + RuleID::EliminateEvalScalar => Ok(Box::new(RuleEliminateEvalScalar::new(metadata))), RuleID::PushDownFilterUnion => Ok(Box::new(RulePushDownFilterUnion::new())), RuleID::PushDownFilterEvalScalar => Ok(Box::new(RulePushDownFilterEvalScalar::new())), RuleID::PushDownFilterJoin => Ok(Box::new(RulePushDownFilterJoin::new(metadata))), @@ -68,6 +69,9 @@ impl RuleFactory { RuleID::PushDownLimitUnion => Ok(Box::new(RulePushDownLimitUnion::new())), RuleID::PushDownLimitScan => Ok(Box::new(RulePushDownLimitScan::new())), RuleID::PushDownSortScan => Ok(Box::new(RulePushDownSortScan::new())), + RuleID::PushDownSortEvalScalar => { + Ok(Box::new(RulePushDownSortEvalScalar::new(metadata))) + } RuleID::PushDownLimitOuterJoin => Ok(Box::new(RulePushDownLimitOuterJoin::new())), RuleID::PushDownLimitEvalScalar => Ok(Box::new(RulePushDownLimitEvalScalar::new())), RuleID::PushDownLimitSort => { diff --git a/src/query/sql/src/planner/optimizer/rule/rewrite/mod.rs b/src/query/sql/src/planner/optimizer/rule/rewrite/mod.rs index a24e3bc2e018..1e55479e3a93 100644 --- a/src/query/sql/src/planner/optimizer/rule/rewrite/mod.rs +++ b/src/query/sql/src/planner/optimizer/rule/rewrite/mod.rs @@ -39,6 +39,7 @@ mod rule_push_down_limit_sort; mod rule_push_down_limit_union; mod rule_push_down_limit_window; mod rule_push_down_prewhere; +mod rule_push_down_sort_expression; mod rule_push_down_sort_scan; mod rule_semi_to_inner_join; mod rule_split_aggregate; @@ -70,6 +71,7 @@ pub use rule_push_down_limit_sort::RulePushDownLimitSort; pub use rule_push_down_limit_union::RulePushDownLimitUnion; pub use rule_push_down_limit_window::RulePushDownLimitWindow; pub use rule_push_down_prewhere::RulePushDownPrewhere; +pub use rule_push_down_sort_expression::RulePushDownSortEvalScalar; pub use rule_push_down_sort_scan::RulePushDownSortScan; pub use rule_semi_to_inner_join::RuleSemiToInnerJoin; pub use rule_split_aggregate::RuleSplitAggregate; diff --git a/src/query/sql/src/planner/optimizer/rule/rewrite/rule_eliminate_eval_scalar.rs b/src/query/sql/src/planner/optimizer/rule/rewrite/rule_eliminate_eval_scalar.rs index 6f0a3295c83d..f079779c5b79 100644 --- a/src/query/sql/src/planner/optimizer/rule/rewrite/rule_eliminate_eval_scalar.rs +++ b/src/query/sql/src/planner/optimizer/rule/rewrite/rule_eliminate_eval_scalar.rs @@ -18,17 +18,22 @@ use crate::optimizer::extract::Matcher; use crate::optimizer::rule::Rule; use crate::optimizer::rule::RuleID; use crate::optimizer::rule::TransformResult; +use crate::optimizer::RelExpr; use crate::optimizer::SExpr; use crate::plans::EvalScalar; +use crate::plans::Operator; use crate::plans::RelOp; +use crate::ColumnSet; +use crate::MetadataRef; pub struct RuleEliminateEvalScalar { id: RuleID, matchers: Vec, + metadata: MetadataRef, } impl RuleEliminateEvalScalar { - pub fn new() -> Self { + pub fn new(metadata: MetadataRef) -> Self { Self { id: RuleID::EliminateEvalScalar, // EvalScalar @@ -38,6 +43,7 @@ impl RuleEliminateEvalScalar { op_type: RelOp::EvalScalar, children: vec![Matcher::Leaf], }], + metadata, } } } @@ -48,13 +54,29 @@ impl Rule for RuleEliminateEvalScalar { } fn apply(&self, s_expr: &SExpr, state: &mut TransformResult) -> Result<()> { - let eval_scalar: EvalScalar = s_expr.plan().clone().try_into()?; - // Eliminate empty EvalScalar + let eval_scalar: EvalScalar = s_expr.plan().clone().try_into()?; if eval_scalar.items.is_empty() { state.add_result(s_expr.child(0)?.clone()); return Ok(()); } + + if self.metadata.read().has_agg_indexes() { + return Ok(()); + } + + let child = s_expr.child(0)?; + let child_output_cols = child + .plan() + .derive_relational_prop(&RelExpr::with_s_expr(child))? + .output_columns + .clone(); + let eval_scalar_output_cols: ColumnSet = + eval_scalar.items.iter().map(|x| x.index).collect(); + if eval_scalar_output_cols.is_subset(&child_output_cols) { + state.add_result(s_expr.child(0)?.clone()); + return Ok(()); + } Ok(()) } diff --git a/src/query/sql/src/planner/optimizer/rule/rewrite/rule_push_down_sort_expression.rs b/src/query/sql/src/planner/optimizer/rule/rewrite/rule_push_down_sort_expression.rs new file mode 100644 index 000000000000..6e6902c2e43a --- /dev/null +++ b/src/query/sql/src/planner/optimizer/rule/rewrite/rule_push_down_sort_expression.rs @@ -0,0 +1,104 @@ +// Copyright 2021 Datafuse Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::sync::Arc; + +use crate::optimizer::extract::Matcher; +use crate::optimizer::rule::Rule; +use crate::optimizer::rule::TransformResult; +use crate::optimizer::RelExpr; +use crate::optimizer::RuleID; +use crate::optimizer::SExpr; +use crate::plans::EvalScalar; +use crate::plans::RelOp; +use crate::plans::RelOperator; +use crate::plans::Sort; +use crate::MetadataRef; + +/// Input: Order by +/// \ +/// Expression +/// \ +/// * +/// +/// Output: Expression +/// \ +/// Order By +/// \ +/// * +pub struct RulePushDownSortEvalScalar { + id: RuleID, + matchers: Vec, + metadata: MetadataRef, +} + +impl RulePushDownSortEvalScalar { + pub fn new(metadata: MetadataRef) -> Self { + Self { + id: RuleID::PushDownSortEvalScalar, + matchers: vec![Matcher::MatchOp { + op_type: RelOp::Sort, + children: vec![Matcher::MatchOp { + op_type: RelOp::EvalScalar, + children: vec![Matcher::Leaf], + }], + }], + metadata, + } + } +} + +impl Rule for RulePushDownSortEvalScalar { + fn id(&self) -> RuleID { + self.id + } + + fn apply( + &self, + s_expr: &SExpr, + state: &mut TransformResult, + ) -> databend_common_exception::Result<()> { + // If lazy materialization isn't enabled, we don't need push down the sort expression. + if self.metadata.read().lazy_columns().is_empty() { + return Ok(()); + } + let sort: Sort = s_expr.plan().clone().try_into()?; + let eval_plan = s_expr.child(0)?; + let eval_child_output_cols = &RelExpr::with_s_expr(eval_plan.child(0)?) + .derive_relational_prop()? + .output_columns; + // Check if the sort expression is a subset of the output columns of the eval child plan. + if !sort.used_columns().is_subset(eval_child_output_cols) { + return Ok(()); + } + let eval_scalar: EvalScalar = eval_plan.plan().clone().try_into()?; + + let sort_expr = SExpr::create_unary( + Arc::new(RelOperator::Sort(sort)), + Arc::new(eval_plan.child(0)?.clone()), + ); + let mut result = SExpr::create_unary( + Arc::new(RelOperator::EvalScalar(eval_scalar)), + Arc::new(sort_expr), + ); + + result.set_applied_rule(&self.id); + state.add_result(result); + Ok(()) + } + + fn matchers(&self) -> &[Matcher] { + &self.matchers + } +} diff --git a/src/query/sql/src/planner/optimizer/rule/rewrite/rule_push_down_sort_scan.rs b/src/query/sql/src/planner/optimizer/rule/rewrite/rule_push_down_sort_scan.rs index 4c7992ff10ca..bc17984429da 100644 --- a/src/query/sql/src/planner/optimizer/rule/rewrite/rule_push_down_sort_scan.rs +++ b/src/query/sql/src/planner/optimizer/rule/rewrite/rule_push_down_sort_scan.rs @@ -24,7 +24,6 @@ use crate::optimizer::RuleID; use crate::optimizer::SExpr; use crate::plans::RelOp; use crate::plans::RelOperator; -use crate::plans::Scan; use crate::plans::Sort; /// Input: Sort @@ -44,13 +43,25 @@ impl RulePushDownSortScan { pub fn new() -> Self { Self { id: RuleID::PushDownSortScan, - matchers: vec![Matcher::MatchOp { - op_type: RelOp::Sort, - children: vec![Matcher::MatchOp { - op_type: RelOp::Scan, - children: vec![], - }], - }], + matchers: vec![ + Matcher::MatchOp { + op_type: RelOp::Sort, + children: vec![Matcher::MatchOp { + op_type: RelOp::Scan, + children: vec![], + }], + }, + Matcher::MatchOp { + op_type: RelOp::Sort, + children: vec![Matcher::MatchOp { + op_type: RelOp::EvalScalar, + children: vec![Matcher::MatchOp { + op_type: RelOp::Scan, + children: vec![], + }], + }], + }, + ], } } } @@ -63,16 +74,32 @@ impl Rule for RulePushDownSortScan { fn apply(&self, s_expr: &SExpr, state: &mut TransformResult) -> Result<()> { let sort: Sort = s_expr.plan().clone().try_into()?; let child = s_expr.child(0)?; - let mut get: Scan = child.plan().clone().try_into()?; + let mut get = match child.plan() { + RelOperator::Scan(scan) => scan.clone(), + RelOperator::EvalScalar(_) => { + let child = child.child(0)?; + child.plan().clone().try_into()? + } + _ => unreachable!(), + }; if get.order_by.is_none() { get.order_by = Some(sort.items); } if let Some(limit) = sort.limit { get.limit = Some(get.limit.map_or(limit, |c| cmp::max(c, limit))); } + let get = SExpr::create_leaf(Arc::new(RelOperator::Scan(get))); - let mut result = s_expr.replace_children(vec![Arc::new(get)]); + let mut result = match child.plan() { + RelOperator::Scan(_) => s_expr.replace_children(vec![Arc::new(get)]), + RelOperator::EvalScalar(_) => { + let child = child.replace_children(vec![Arc::new(get)]); + s_expr.replace_children(vec![Arc::new(child)]) + } + _ => unreachable!(), + }; + result.set_applied_rule(&self.id); state.add_result(result); Ok(()) diff --git a/src/query/sql/src/planner/optimizer/rule/rule.rs b/src/query/sql/src/planner/optimizer/rule/rule.rs index 4d2704cafd1c..fb19eee25c4a 100644 --- a/src/query/sql/src/planner/optimizer/rule/rule.rs +++ b/src/query/sql/src/planner/optimizer/rule/rule.rs @@ -42,6 +42,7 @@ pub static DEFAULT_REWRITE_RULES: LazyLock> = LazyLock::new(|| { RuleID::PushDownFilterProjectSet, RuleID::PushDownLimit, RuleID::PushDownLimitUnion, + RuleID::PushDownSortEvalScalar, RuleID::PushDownLimitEvalScalar, RuleID::PushDownLimitSort, RuleID::PushDownLimitWindow, @@ -94,6 +95,7 @@ pub enum RuleID { PushDownLimitWindow, PushDownLimitAggregate, PushDownLimitScan, + PushDownSortEvalScalar, PushDownSortScan, SemiToInnerJoin, EliminateEvalScalar, @@ -131,6 +133,7 @@ impl Display for RuleID { RuleID::PushDownFilterAggregate => write!(f, "PushDownFilterAggregate"), RuleID::PushDownLimitScan => write!(f, "PushDownLimitScan"), RuleID::PushDownSortScan => write!(f, "PushDownSortScan"), + RuleID::PushDownSortEvalScalar => write!(f, "PushDownSortEvalScalar"), RuleID::PushDownLimitWindow => write!(f, "PushDownLimitWindow"), RuleID::PushDownFilterWindow => write!(f, "PushDownFilterWindow"), RuleID::EliminateEvalScalar => write!(f, "EliminateEvalScalar"), diff --git a/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs b/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs index c3c9ec322f96..9f04d669d98e 100644 --- a/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs +++ b/src/query/sql/src/planner/optimizer/statistics/collect_statistics.rs @@ -151,7 +151,7 @@ impl CollectStatisticsOptimizer { RelOperator::MaterializedCte(materialized_cte) => { // Collect the common table expression statistics first. let right = Box::pin(self.collect(s_expr.child(1)?)).await?; - let cte_stat_info = RelExpr::with_s_expr(&right).derive_cardinality_child(0)?; + let cte_stat_info = RelExpr::with_s_expr(&right).derive_cardinality()?; self.cte_statistics .insert(materialized_cte.cte_idx, cte_stat_info); let left = Box::pin(self.collect(s_expr.child(0)?)).await?; diff --git a/src/query/sql/src/planner/plans/sort.rs b/src/query/sql/src/planner/plans/sort.rs index d0a87b6398cc..cc31a7ed5fbe 100644 --- a/src/query/sql/src/planner/plans/sort.rs +++ b/src/query/sql/src/planner/plans/sort.rs @@ -26,6 +26,7 @@ use crate::optimizer::StatInfo; use crate::plans::Operator; use crate::plans::RelOp; use crate::plans::ScalarItem; +use crate::ColumnSet; use crate::IndexType; #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -46,6 +47,10 @@ pub struct Sort { } impl Sort { + pub fn used_columns(&self) -> ColumnSet { + self.items.iter().map(|item| item.index).collect() + } + pub fn sort_items_exclude_partition(&self) -> Vec { self.items .iter() diff --git a/tests/sqllogictests/suites/base/20+_others/20_0001_planner.test b/tests/sqllogictests/suites/base/20+_others/20_0001_planner.test index a63bcac038b4..35adfda51ee6 100644 --- a/tests/sqllogictests/suites/base/20+_others/20_0001_planner.test +++ b/tests/sqllogictests/suites/base/20+_others/20_0001_planner.test @@ -1311,8 +1311,8 @@ insert into t2 values(3, 4), (2, 3), (null, 2) query II select t1.a, (select t2.a from t2 where t1.a > 1 and t2.a > 2) from t1 order by t1.a ---- -2 3 1 NULL +2 3 NULL NULL diff --git a/tests/sqllogictests/suites/ee/02_ee_aggregating_index/02_0000_async_agg_index_base.test b/tests/sqllogictests/suites/ee/02_ee_aggregating_index/02_0000_async_agg_index_base.test index 7ae14f89b18d..2d45787e8f85 100644 --- a/tests/sqllogictests/suites/ee/02_ee_aggregating_index/02_0000_async_agg_index_base.test +++ b/tests/sqllogictests/suites/ee/02_ee_aggregating_index/02_0000_async_agg_index_base.test @@ -458,13 +458,13 @@ Logout 2 2 5.0 query T explain select event_name, user_id, max(user_id), avg(id) from t where user_id > 1 group by event_name, user_id order by event_name, user_id desc ---- -EvalScalar +Sort ├── output columns: [max(user_id) (#3), t.event_name (#2), t.user_id (#1), sum(id) / if(count(id) = 0, 1, count(id)) (#6)] -├── expressions: [sum(id) (#4) / CAST(if(CAST(count(id) (#5) = 0 AS Boolean NULL), 1, count(id) (#5)) AS UInt64 NULL)] +├── sort keys: [event_name ASC NULLS LAST, user_id DESC NULLS LAST] ├── estimated rows: 6.00 -└── Sort - ├── output columns: [max(user_id) (#3), sum(id) (#4), count(id) (#5), t.event_name (#2), t.user_id (#1)] - ├── sort keys: [event_name ASC NULLS LAST, user_id DESC NULLS LAST] +└── EvalScalar + ├── output columns: [max(user_id) (#3), t.event_name (#2), t.user_id (#1), sum(id) / if(count(id) = 0, 1, count(id)) (#6)] + ├── expressions: [sum(id) (#4) / CAST(if(CAST(count(id) (#5) = 0 AS Boolean NULL), 1, count(id) (#5)) AS UInt64 NULL)] ├── estimated rows: 6.00 └── AggregateFinal ├── output columns: [max(user_id) (#3), sum(id) (#4), count(id) (#5), t.event_name (#2), t.user_id (#1)] diff --git a/tests/sqllogictests/suites/mode/cluster/explain_v2.test b/tests/sqllogictests/suites/mode/cluster/explain_v2.test index ddc3693ec5e2..6e1d850fc04d 100644 --- a/tests/sqllogictests/suites/mode/cluster/explain_v2.test +++ b/tests/sqllogictests/suites/mode/cluster/explain_v2.test @@ -309,7 +309,7 @@ Limit ├── read size: < 1 KiB ├── partitions total: 1 ├── partitions scanned: 1 - ├── push downs: [filters: [], limit: NONE] + ├── push downs: [filters: [], limit: 3] └── estimated rows: 10.00 query T diff --git a/tests/sqllogictests/suites/mode/cluster/memo/mix_property.test b/tests/sqllogictests/suites/mode/cluster/memo/mix_property.test index 48a6b30a1ff8..b135f0c753e5 100644 --- a/tests/sqllogictests/suites/mode/cluster/memo/mix_property.test +++ b/tests/sqllogictests/suites/mode/cluster/memo/mix_property.test @@ -29,7 +29,7 @@ limit 10 ---- Memo ├── root group: #10 -├── estimated memory: 12.81 KiB +├── estimated memory: 30.11 KiB ├── Group #0 │ ├── Best properties │ │ ├── { dist: Any }: expr: #0, cost: 1000.000, children: [] @@ -55,7 +55,7 @@ Memo │ │ ├── { dist: Any }: expr: #0, cost: 1310.000, children: [{ dist: Any }, { dist: Broadcast }] │ │ ├── { dist: Broadcast }: expr: #1, cost: 2310.000, children: [{ dist: Any }] │ │ ├── { dist: Hash(t_10.a (#2)::Int32 NULL) }: expr: #2, cost: 1820.000, children: [{ dist: Any }] -│ │ └── { dist: Hash(t_100.a (#1)::Int32 NULL) }: expr: #0, cost: 6410.000, children: [{ dist: Hash(t_100.a (#1)::Int32 NULL) }, { dist: Hash(t_10.a (#2)::Int32 NULL) }] +│ │ └── { dist: Hash(t_100.a (#1)::Int32 NULL) }: expr: #0, cost: 5920.000, children: [{ dist: Hash(t_100.a (#1)::Int32 NULL) }, { dist: Hash(t_10.a (#2)::Int32 NULL) }] │ ├── #0 Join [#1, #2] │ ├── #1 Exchange: (Broadcast) [#3] │ ├── #2 Exchange: (Hash(t_10.a (#2)::Int32 NULL)) [#3] @@ -76,22 +76,105 @@ Memo │ └── #0 Aggregate [#5] ├── Group #7 │ ├── Best properties -│ │ ├── { dist: Any }: expr: #0, cost: 5030.000, children: [{ dist: Any }] -│ │ └── { dist: Serial }: expr: #1, cost: 8530.000, children: [{ dist: Any }] -│ ├── #0 Aggregate [#6] -│ └── #1 Exchange: (Merge) [#7] +│ │ └── { dist: Any }: expr: #0, cost: 5030.000, children: [{ dist: Any }] +│ └── #0 Aggregate [#6] ├── Group #8 │ ├── Best properties -│ │ └── { dist: Serial }: expr: #0, cost: 8540.000, children: [{ dist: Serial }] -│ └── #0 Sort [#7] +│ │ ├── { dist: Any }: expr: #0, cost: 5040.000, children: [{ dist: Any }] +│ │ └── { dist: Serial }: expr: #4, cost: 8540.000, children: [{ dist: Any }] +│ ├── #0 EvalScalar [#7] +│ ├── #1 EvalScalar [#16] +│ ├── #2 EvalScalar [#22] +│ ├── #3 EvalScalar [#26] +│ └── #4 Exchange: (Merge) [#8] ├── Group #9 │ ├── Best properties -│ │ └── { dist: Any }: expr: #0, cost: 8550.000, children: [{ dist: Serial }] -│ └── #0 Limit [#8] -└── Group #10 +│ │ └── { dist: Serial }: expr: #0, cost: 8550.000, children: [{ dist: Serial }] +│ └── #0 Sort [#8] +├── Group #10 +│ ├── Best properties +│ │ └── { dist: Serial }: expr: #0, cost: 8560.000, children: [{ dist: Serial }] +│ └── #0 Limit [#9] +├── Group #11 +│ ├── Best properties +│ │ ├── { dist: Any }: expr: #0, cost: 2000.000, children: [{ dist: Any }] +│ │ └── { dist: Hash(t_1000.a (#0)::Int32 NULL) }: expr: #1, cost: 53000.000, children: [{ dist: Any }] +│ ├── #0 EvalScalar [#0] +│ └── #1 Exchange: (Hash(t_1000.a (#0)::Int32 NULL)) [#11] +├── Group #12 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 58000.000, children: [{ dist: Hash(t_1000.a (#0)::Int32 NULL) }] +│ └── #0 Aggregate [#11] +├── Group #13 +│ ├── Best properties +│ │ ├── { dist: Any }: expr: #0, cost: 63000.000, children: [{ dist: Any }] +│ │ └── { dist: Hash(t_1000.a (#0)::Int32 NULL) }: expr: #1, cost: 114000.000, children: [{ dist: Any }] +│ ├── #0 Aggregate [#12] +│ └── #1 Exchange: (Hash(t_1000.a (#0)::Int32 NULL)) [#13] +├── Group #14 +│ ├── Best properties +│ │ ├── { dist: Any }: expr: #0, cost: 66410.000, children: [{ dist: Any }, { dist: Broadcast }] +│ │ └── { dist: Hash(t_100.a (#1)::Int32 NULL) }: expr: #1, cost: 66920.000, children: [{ dist: Any }] +│ ├── #0 Join [#13, #3] +│ └── #1 Exchange: (Hash(t_100.a (#1)::Int32 NULL)) [#14] +├── Group #15 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 66970.000, children: [{ dist: Hash(t_100.a (#1)::Int32 NULL) }] +│ └── #0 Aggregate [#14] +├── Group #16 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 67020.000, children: [{ dist: Any }] +│ └── #0 Aggregate [#15] +├── Group #17 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 5970.000, children: [{ dist: Hash(t_100.a (#1)::Int32 NULL) }] +│ └── #0 Aggregate [#3] +├── Group #18 +│ ├── Best properties +│ │ ├── { dist: Any }: expr: #0, cost: 6020.000, children: [{ dist: Any }] +│ │ ├── { dist: Broadcast }: expr: #3, cost: 7020.000, children: [{ dist: Any }] +│ │ ├── { dist: Hash(t_10.a (#2)::Int32 NULL) }: expr: #1, cost: 6530.000, children: [{ dist: Any }] +│ │ └── { dist: Hash(t_100.a (#1)::Int32 NULL) }: expr: #2, cost: 6530.000, children: [{ dist: Any }] +│ ├── #0 Aggregate [#17] +│ ├── #1 Exchange: (Hash(t_10.a (#2)::Int32 NULL)) [#18] +│ ├── #2 Exchange: (Hash(t_100.a (#1)::Int32 NULL)) [#18] +│ └── #3 Exchange: (Broadcast) [#18] +├── Group #19 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 9120.000, children: [{ dist: Any }, { dist: Broadcast }] +│ └── #0 Join [#0, #18] +├── Group #20 +│ ├── Best properties +│ │ ├── { dist: Any }: expr: #0, cost: 9130.000, children: [{ dist: Any }] +│ │ └── { dist: Hash(t_100.a (#1)::Int32 NULL) }: expr: #1, cost: 9640.000, children: [{ dist: Any }] +│ ├── #0 EvalScalar [#19] +│ └── #1 Exchange: (Hash(t_100.a (#1)::Int32 NULL)) [#20] +├── Group #21 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 9690.000, children: [{ dist: Hash(t_100.a (#1)::Int32 NULL) }] +│ └── #0 Aggregate [#20] +├── Group #22 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 9740.000, children: [{ dist: Any }] +│ └── #0 Aggregate [#21] +├── Group #23 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 71120.000, children: [{ dist: Any }, { dist: Broadcast }] +│ └── #0 Join [#13, #18] +├── Group #24 +│ ├── Best properties +│ │ ├── { dist: Any }: expr: #0, cost: 71130.000, children: [{ dist: Any }] +│ │ └── { dist: Hash(t_100.a (#1)::Int32 NULL) }: expr: #1, cost: 71640.000, children: [{ dist: Any }] +│ ├── #0 EvalScalar [#23] +│ └── #1 Exchange: (Hash(t_100.a (#1)::Int32 NULL)) [#24] +├── Group #25 +│ ├── Best properties +│ │ └── { dist: Any }: expr: #0, cost: 71690.000, children: [{ dist: Hash(t_100.a (#1)::Int32 NULL) }] +│ └── #0 Aggregate [#24] +└── Group #26 ├── Best properties - │ └── { dist: Serial }: expr: #0, cost: 8560.000, children: [{ dist: Any }] - └── #0 EvalScalar [#9] + │ └── { dist: Any }: expr: #0, cost: 71740.000, children: [{ dist: Any }] + └── #0 Aggregate [#25] statement ok diff --git a/tests/sqllogictests/suites/mode/cluster/window.test b/tests/sqllogictests/suites/mode/cluster/window.test index 2e3089b53fdc..fd8f6e106600 100644 --- a/tests/sqllogictests/suites/mode/cluster/window.test +++ b/tests/sqllogictests/suites/mode/cluster/window.test @@ -128,44 +128,40 @@ explain select number, lead(number,1, 0) over (partition by number % 3 order by from numbers(50); ---- Exchange -├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 1, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 2, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#5)] +├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 1, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), lead(number, 2, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#5)] ├── exchange type: Merge └── Window - ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 1, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 2, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#5)] + ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 1, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), lead(number, 2, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#5)] ├── aggregate function: [lead] ├── partition by: [lead_part_0] ├── order by: [lead_order_0] ├── frame: [Rows: Following(Some(Number(2_u64))) ~ Following(Some(Number(2_u64)))] - └── EvalScalar - ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 1, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3)] - ├── expressions: [0, numbers.number (#0) % 3, numbers.number (#0) + 1] - ├── estimated rows: 50.00 - └── Window - ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 1, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4)] - ├── aggregate function: [lead] - ├── partition by: [lead_part_0] - ├── order by: [lead_order_0] - ├── frame: [Rows: Following(Some(Number(1_u64))) ~ Following(Some(Number(1_u64)))] - └── WindowPartition + └── Window + ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3), lead(number, 1, 0) OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4)] + ├── aggregate function: [lead] + ├── partition by: [lead_part_0] + ├── order by: [lead_order_0] + ├── frame: [Rows: Following(Some(Number(1_u64))) ~ Following(Some(Number(1_u64)))] + └── WindowPartition + ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3)] + ├── hash keys: [lead_part_0] + ├── estimated rows: 50.00 + └── Exchange ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3)] - ├── hash keys: [lead_part_0] - ├── estimated rows: 50.00 - └── Exchange + ├── exchange type: Hash(numbers.number (#0) % 3) + └── EvalScalar ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3)] - ├── exchange type: Hash(numbers.number (#0) % 3) - └── EvalScalar - ├── output columns: [numbers.number (#0), lead_default_value (#1), lead_part_0 (#2), lead_order_0 (#3)] - ├── expressions: [0, numbers.number (#0) % 3, numbers.number (#0) + 1] - ├── estimated rows: 50.00 - └── TableScan - ├── table: default.system.numbers - ├── output columns: [number (#0)] - ├── read rows: 50 - ├── read size: < 1 KiB - ├── partitions total: 1 - ├── partitions scanned: 1 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 50.00 + ├── expressions: [0, numbers.number (#0) % 3, numbers.number (#0) + 1] + ├── estimated rows: 50.00 + └── TableScan + ├── table: default.system.numbers + ├── output columns: [number (#0)] + ├── read rows: 50 + ├── read size: < 1 KiB + ├── partitions total: 1 + ├── partitions scanned: 1 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 50.00 statement ok CREATE OR REPLACE TABLE sales ( @@ -187,54 +183,50 @@ ORDER BY diff_from_overall_avg DESC, customer_id ASC LIMIT 10; ---- -EvalScalar -├── output columns: [sales.customer_id (#2), diff_from_overall_avg (#9), customer_avg (#8)] -├── expressions: [round(3)(AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), 3)] +Limit +├── output columns: [sales.customer_id (#2), customer_avg (#8), diff_from_overall_avg (#9)] +├── limit: 10 +├── offset: 0 ├── estimated rows: 0.00 -└── Limit - ├── output columns: [sales.customer_id (#2), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), diff_from_overall_avg (#9)] - ├── limit: 10 - ├── offset: 0 +└── Sort + ├── output columns: [sales.customer_id (#2), customer_avg (#8), diff_from_overall_avg (#9)] + ├── sort keys: [diff_from_overall_avg DESC NULLS LAST, customer_id ASC NULLS LAST] ├── estimated rows: 0.00 - └── Sort - ├── output columns: [sales.customer_id (#2), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), diff_from_overall_avg (#9)] - ├── sort keys: [diff_from_overall_avg DESC NULLS LAST, customer_id ASC NULLS LAST] + └── EvalScalar + ├── output columns: [sales.customer_id (#2), customer_avg (#8), diff_from_overall_avg (#9)] + ├── expressions: [round(3)(AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), 3), round(3)(AVG(net_paid) OVER ( ) (#7) - AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), 3)] ├── estimated rows: 0.00 - └── EvalScalar - ├── output columns: [sales.customer_id (#2), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), diff_from_overall_avg (#9)] - ├── expressions: [round(3)(AVG(net_paid) OVER ( ) (#7) - AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), 3)] - ├── estimated rows: 0.00 - └── Window - ├── output columns: [sales.customer_id (#2), sales.net_paid (#5), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), AVG(net_paid) OVER ( ) (#7)] - ├── aggregate function: [avg(net_paid)] - ├── partition by: [] - ├── order by: [] - ├── frame: [Range: Preceding(None) ~ Following(None)] - └── Exchange + └── Window + ├── output columns: [sales.customer_id (#2), sales.net_paid (#5), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6), AVG(net_paid) OVER ( ) (#7)] + ├── aggregate function: [avg(net_paid)] + ├── partition by: [] + ├── order by: [] + ├── frame: [Range: Preceding(None) ~ Following(None)] + └── Exchange + ├── output columns: [sales.customer_id (#2), sales.net_paid (#5), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6)] + ├── exchange type: Merge + └── Window ├── output columns: [sales.customer_id (#2), sales.net_paid (#5), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6)] - ├── exchange type: Merge - └── Window - ├── output columns: [sales.customer_id (#2), sales.net_paid (#5), AVG(net_paid) OVER ( PARTITION BY customer_id ) (#6)] - ├── aggregate function: [avg(net_paid)] - ├── partition by: [customer_id] - ├── order by: [] - ├── frame: [Range: Preceding(None) ~ Following(None)] - └── WindowPartition + ├── aggregate function: [avg(net_paid)] + ├── partition by: [customer_id] + ├── order by: [] + ├── frame: [Range: Preceding(None) ~ Following(None)] + └── WindowPartition + ├── output columns: [sales.customer_id (#2), sales.net_paid (#5)] + ├── hash keys: [customer_id] + ├── estimated rows: 0.00 + └── Exchange ├── output columns: [sales.customer_id (#2), sales.net_paid (#5)] - ├── hash keys: [customer_id] - ├── estimated rows: 0.00 - └── Exchange - ├── output columns: [sales.customer_id (#2), sales.net_paid (#5)] - ├── exchange type: Hash(sales.customer_id (#2)) - └── TableScan - ├── table: default.default.sales - ├── output columns: [customer_id (#2), net_paid (#5)] - ├── read rows: 0 - ├── read size: 0 - ├── partitions total: 0 - ├── partitions scanned: 0 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 0.00 + ├── exchange type: Hash(sales.customer_id (#2)) + └── TableScan + ├── table: default.default.sales + ├── output columns: [customer_id (#2), net_paid (#5)] + ├── read rows: 0 + ├── read size: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 0.00 statement ok diff --git a/tests/sqllogictests/suites/mode/standalone/ee/explain_agg_index.test b/tests/sqllogictests/suites/mode/standalone/ee/explain_agg_index.test index 1c759079cf14..e9baa6419c0d 100644 --- a/tests/sqllogictests/suites/mode/standalone/ee/explain_agg_index.test +++ b/tests/sqllogictests/suites/mode/standalone/ee/explain_agg_index.test @@ -357,13 +357,13 @@ CREATE AGGREGATING INDEX idx1 as SELECT station_name, MIN(measurement) AS min_me query T EXPLAIN SELECT station_name, MIN(measurement) AS min_measurement, AVG(measurement) AS mean_measurement, MAX(measurement) AS max_measurement FROM onebrc GROUP BY station_name ORDER BY station_name ---- -EvalScalar +Sort ├── output columns: [MIN(measurement) (#5), MAX(measurement) (#8), onebrc.station_name (#0), mean_measurement (#9)] -├── expressions: [sum(measurement) (#6) / CAST(if(CAST(count(measurement) (#7) = 0 AS Boolean NULL), 1, count(measurement) (#7)) AS UInt64 NULL)] +├── sort keys: [station_name ASC NULLS LAST] ├── estimated rows: 0.00 -└── Sort - ├── output columns: [MIN(measurement) (#5), sum(measurement) (#6), count(measurement) (#7), MAX(measurement) (#8), onebrc.station_name (#0)] - ├── sort keys: [station_name ASC NULLS LAST] +└── EvalScalar + ├── output columns: [MIN(measurement) (#5), MAX(measurement) (#8), onebrc.station_name (#0), mean_measurement (#9)] + ├── expressions: [sum(measurement) (#6) / CAST(if(CAST(count(measurement) (#7) = 0 AS Boolean NULL), 1, count(measurement) (#7)) AS UInt64 NULL)] ├── estimated rows: 0.00 └── AggregateFinal ├── output columns: [MIN(measurement) (#5), sum(measurement) (#6), count(measurement) (#7), MAX(measurement) (#8), onebrc.station_name (#0)] @@ -765,8 +765,6 @@ Sort ├── partitions total: 0 ├── partitions scanned: 0 ├── push downs: [filters: [], limit: NONE] - ├── aggregating index: [SELECT a + 1 FROM test_index_db.t1] - ├── rewritten query: [selection: [index_col_0 (#0)]] └── estimated rows: 0.00 statement ok diff --git a/tests/sqllogictests/suites/mode/standalone/explain/aggregate.test b/tests/sqllogictests/suites/mode/standalone/explain/aggregate.test index b04b904bbf36..3ed683ff898e 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/aggregate.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/aggregate.test @@ -214,173 +214,153 @@ EvalScalar query T explain select avg(b) from explain_agg_t1 group by a order by avg(b); ---- -EvalScalar -├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4)] -├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] +Sort +├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] +├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] ├── estimated rows: 0.00 -└── Sort - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] - ├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] +└── EvalScalar + ├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] + ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL), sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] ├── estimated rows: 0.00 - └── EvalScalar - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] - ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] + └── AggregateFinal + ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + ├── group by: [a] + ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregateFinal - ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + └── AggregatePartial ├── group by: [a] ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregatePartial - ├── group by: [a] - ├── aggregate functions: [sum(b), count()] - ├── estimated rows: 0.00 - └── TableScan - ├── table: default.default.explain_agg_t1 - ├── output columns: [a (#0), b (#1)] - ├── read rows: 0 - ├── read size: 0 - ├── partitions total: 0 - ├── partitions scanned: 0 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 0.00 + └── TableScan + ├── table: default.default.explain_agg_t1 + ├── output columns: [a (#0), b (#1)] + ├── read rows: 0 + ├── read size: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 0.00 query T explain select avg(b) + 1 from explain_agg_t1 group by a order by avg(b); ---- -EvalScalar -├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#4)] -├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1] +Sort +├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#4), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] +├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] ├── estimated rows: 0.00 -└── Sort - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] - ├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] +└── EvalScalar + ├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#4), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] + ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1, sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] ├── estimated rows: 0.00 - └── EvalScalar - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] - ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] + └── AggregateFinal + ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + ├── group by: [a] + ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregateFinal - ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + └── AggregatePartial ├── group by: [a] ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregatePartial - ├── group by: [a] - ├── aggregate functions: [sum(b), count()] - ├── estimated rows: 0.00 - └── TableScan - ├── table: default.default.explain_agg_t1 - ├── output columns: [a (#0), b (#1)] - ├── read rows: 0 - ├── read size: 0 - ├── partitions total: 0 - ├── partitions scanned: 0 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 0.00 + └── TableScan + ├── table: default.default.explain_agg_t1 + ├── output columns: [a (#0), b (#1)] + ├── read rows: 0 + ├── read size: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 0.00 query T explain select avg(b), avg(b) + 1 from explain_agg_t1 group by a order by avg(b); ---- -EvalScalar -├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#5)] -├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL), sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1] +Sort +├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#5), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] +├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] ├── estimated rows: 0.00 -└── Sort - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] - ├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] +└── EvalScalar + ├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#5), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] + ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL), sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1, sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] ├── estimated rows: 0.00 - └── EvalScalar - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] - ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] + └── AggregateFinal + ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + ├── group by: [a] + ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregateFinal - ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + └── AggregatePartial ├── group by: [a] ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregatePartial - ├── group by: [a] - ├── aggregate functions: [sum(b), count()] - ├── estimated rows: 0.00 - └── TableScan - ├── table: default.default.explain_agg_t1 - ├── output columns: [a (#0), b (#1)] - ├── read rows: 0 - ├── read size: 0 - ├── partitions total: 0 - ├── partitions scanned: 0 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 0.00 + └── TableScan + ├── table: default.default.explain_agg_t1 + ├── output columns: [a (#0), b (#1)] + ├── read rows: 0 + ├── read size: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 0.00 query T explain select avg(b) + 1, avg(b) from explain_agg_t1 group by a order by avg(b); ---- -EvalScalar -├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#4), sum(b) / if(count(b) = 0, 1, count(b)) (#5)] -├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1, sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] +Sort +├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#4), sum(b) / if(count(b) = 0, 1, count(b)) (#5), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] +├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] ├── estimated rows: 0.00 -└── Sort - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] - ├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) ASC NULLS LAST] +└── EvalScalar + ├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#4), sum(b) / if(count(b) = 0, 1, count(b)) (#5), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] + ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1, sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL), sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] ├── estimated rows: 0.00 - └── EvalScalar - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) (#6)] - ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL)] + └── AggregateFinal + ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + ├── group by: [a] + ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregateFinal - ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + └── AggregatePartial ├── group by: [a] ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregatePartial - ├── group by: [a] - ├── aggregate functions: [sum(b), count()] - ├── estimated rows: 0.00 - └── TableScan - ├── table: default.default.explain_agg_t1 - ├── output columns: [a (#0), b (#1)] - ├── read rows: 0 - ├── read size: 0 - ├── partitions total: 0 - ├── partitions scanned: 0 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 0.00 + └── TableScan + ├── table: default.default.explain_agg_t1 + ├── output columns: [a (#0), b (#1)] + ├── read rows: 0 + ├── read size: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 0.00 query T explain select avg(b), avg(b) + 1 from explain_agg_t1 group by a order by avg(b) + 1; ---- -EvalScalar -├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#5)] -├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL), sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1] +Sort +├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#5), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#6)] +├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 ASC NULLS LAST] ├── estimated rows: 0.00 -└── Sort - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#6)] - ├── sort keys: [sum(b) / if(count(b) = 0, 1, count(b)) + 1 ASC NULLS LAST] +└── EvalScalar + ├── output columns: [sum(b) / if(count(b) = 0, 1, count(b)) (#4), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#5), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#6)] + ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL), sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1, sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1] ├── estimated rows: 0.00 - └── EvalScalar - ├── output columns: [sum(b) (#2), count(b) (#3), sum(b) / if(count(b) = 0, 1, count(b)) + 1 (#6)] - ├── expressions: [sum(b) (#2) / CAST(if(CAST(count(b) (#3) = 0 AS Boolean NULL), 1, count(b) (#3)) AS UInt64 NULL) + 1] + └── AggregateFinal + ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + ├── group by: [a] + ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregateFinal - ├── output columns: [sum(b) (#2), count(b) (#3), explain_agg_t1.a (#0)] + └── AggregatePartial ├── group by: [a] ├── aggregate functions: [sum(b), count()] ├── estimated rows: 0.00 - └── AggregatePartial - ├── group by: [a] - ├── aggregate functions: [sum(b), count()] - ├── estimated rows: 0.00 - └── TableScan - ├── table: default.default.explain_agg_t1 - ├── output columns: [a (#0), b (#1)] - ├── read rows: 0 - ├── read size: 0 - ├── partitions total: 0 - ├── partitions scanned: 0 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 0.00 + └── TableScan + ├── table: default.default.explain_agg_t1 + ├── output columns: [a (#0), b (#1)] + ├── read rows: 0 + ├── read size: 0 + ├── partitions total: 0 + ├── partitions scanned: 0 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 0.00 statement ok drop table explain_agg_t1; @@ -475,4 +455,4 @@ statement ok DROP TABLE IF EXISTS t; statement ok -DROP TABLE IF EXISTS explain_agg_t1; \ No newline at end of file +DROP TABLE IF EXISTS explain_agg_t1; diff --git a/tests/sqllogictests/suites/mode/standalone/explain/explain.test b/tests/sqllogictests/suites/mode/standalone/explain/explain.test index 9f5f9909c98d..940d94cf1aac 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/explain.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/explain.test @@ -322,7 +322,7 @@ query T explain syntax with cte (a, b) as (select 1, 2 union all select 3, 4) select a, b from cte ---- WITH - cte(a, b) AS + cte(a, b) AS ( SELECT 1, @@ -341,7 +341,7 @@ query T explain syntax with cte (a, b) as (values(1,2),(3,4)) select a, b from cte ---- WITH - cte(a, b) AS + cte(a, b) AS ( VALUES(1, 2), (3, 4) ) @@ -1037,7 +1037,7 @@ Sort ├── output columns: [numbers.number (#0), pt (#1), register_at (#3)] ├── join type: INNER ├── build keys: [b.register_at (#3), numbers.number (#2)] - ├── probe keys: [a.pt (#1), numbers.number (#0)] + ├── probe keys: [a.pt (#1), a.number (#0)] ├── filters: [] ├── estimated rows: 0.00 ├── EvalScalar(Build) @@ -1266,21 +1266,19 @@ Sort query T EXPLAIN optimized SELECT * FROM t1 LEFT OUTER JOIN t2 ON TRUE AND t1.i = t2.k AND FALSE order by i, j; ---- -EvalScalar -├── scalars: [t1.i (#0) AS (#0), t1.j (#1) AS (#1), t2.k (#2) AS (#2), t2.l (#3) AS (#3)] -└── Sort - ├── sort keys: [default.t1.i (#0) ASC, default.t1.j (#1) ASC] - ├── limit: [NONE] - └── Join(Left) - ├── build keys: [t2.k (#2)] - ├── probe keys: [t1.i (#0)] - ├── other filters: [] - ├── Scan - │ ├── table: default.t1 - │ ├── filters: [] - │ ├── order by: [] - │ └── limit: NONE - └── EmptyResultScan +Sort +├── sort keys: [default.t1.i (#0) ASC, default.t1.j (#1) ASC] +├── limit: [NONE] +└── Join(Left) + ├── build keys: [t2.k (#2)] + ├── probe keys: [t1.i (#0)] + ├── other filters: [] + ├── Scan + │ ├── table: default.t1 + │ ├── filters: [] + │ ├── order by: [] + │ └── limit: NONE + └── EmptyResultScan statement ok @@ -1621,13 +1619,11 @@ InsertPlan (subquery): ├── table: default.default.t2 ├── inserted columns: [t2.a (#0),t2.b (#1),t2.c (#2)] ├── overwrite: false -└── EvalScalar - ├── scalars: [t1.a (#0) AS (#0), t1.b (#1) AS (#1), t1.c (#2) AS (#2)] - └── Scan - ├── table: default.t1 - ├── filters: [] - ├── order by: [] - └── limit: NONE +└── Scan + ├── table: default.t1 + ├── filters: [] + ├── order by: [] + └── limit: NONE statement ok diff --git a/tests/sqllogictests/suites/mode/standalone/explain/explain_verbose.test b/tests/sqllogictests/suites/mode/standalone/explain/explain_verbose.test index 43174548b5ef..a9907e922a4d 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/explain_verbose.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/explain_verbose.test @@ -47,8 +47,8 @@ EvalScalar query T explain(verbose, logical, optimized) select * from t where a = 1 ---- -EvalScalar -├── scalars: [t.a (#0) AS (#0), t.b (#1) AS (#1)] +Filter +├── filters: [eq(t.a (#0), 1)] ├── output columns: [testdb.t.a, testdb.t.b] ├── outer columns: [] ├── used columns: [testdb.t.a, testdb.t.b] @@ -57,36 +57,28 @@ EvalScalar ├── statistics │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } -└── Filter +└── Scan + ├── table: testdb.t ├── filters: [eq(t.a (#0), 1)] + ├── order by: [] + ├── limit: NONE ├── output columns: [testdb.t.a, testdb.t.b] ├── outer columns: [] ├── used columns: [testdb.t.a, testdb.t.b] - ├── cardinality: 1.000 - ├── precise cardinality: N/A - ├── statistics - │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - └── Scan - ├── table: testdb.t - ├── filters: [eq(t.a (#0), 1)] - ├── order by: [] - ├── limit: NONE - ├── output columns: [testdb.t.a, testdb.t.b] - ├── outer columns: [] - ├── used columns: [testdb.t.a, testdb.t.b] - ├── cardinality: 1000.000 - ├── precise cardinality: 1000 - └── statistics - ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } - └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } + ├── cardinality: 1000.000 + ├── precise cardinality: 1000 + └── statistics + ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } + └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } query T explain(verbose, logical, optimized) select * from t, t t1, t t2, t t3, t t4 where t.a = 1 and t1.a = 1 and t2.a = 1 and t3.a = 1 and t4.a = 1 ---- -EvalScalar -├── scalars: [t.a (#0) AS (#0), t.b (#1) AS (#1), t1.a (#2) AS (#2), t1.b (#3) AS (#3), t2.a (#4) AS (#4), t2.b (#5) AS (#5), t3.a (#6) AS (#6), t3.b (#7) AS (#7), t4.a (#8) AS (#8), t4.b (#9) AS (#9)] +Join(Cross) +├── build keys: [] +├── probe keys: [] +├── other filters: [] ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] ├── outer columns: [] ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] @@ -103,189 +95,169 @@ EvalScalar │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } -└── Join(Cross) - ├── build keys: [] - ├── probe keys: [] - ├── other filters: [] - ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] +├── Join(Cross) +│ ├── build keys: [] +│ ├── probe keys: [] +│ ├── other filters: [] +│ ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] +│ ├── outer columns: [] +│ ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] +│ ├── cardinality: 1.000 +│ ├── precise cardinality: N/A +│ ├── statistics +│ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ ├── Join(Cross) +│ │ ├── build keys: [] +│ │ ├── probe keys: [] +│ │ ├── other filters: [] +│ │ ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b] +│ │ ├── outer columns: [] +│ │ ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b] +│ │ ├── cardinality: 1.000 +│ │ ├── precise cardinality: N/A +│ │ ├── statistics +│ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ ├── Join(Cross) +│ │ │ ├── build keys: [] +│ │ │ ├── probe keys: [] +│ │ │ ├── other filters: [] +│ │ │ ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b] +│ │ │ ├── outer columns: [] +│ │ │ ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b] +│ │ │ ├── cardinality: 1.000 +│ │ │ ├── precise cardinality: N/A +│ │ │ ├── statistics +│ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ │ ├── Filter +│ │ │ │ ├── filters: [eq(t.a (#0), 1)] +│ │ │ │ ├── output columns: [testdb.t.a, testdb.t.b] +│ │ │ │ ├── outer columns: [] +│ │ │ │ ├── used columns: [testdb.t.a, testdb.t.b] +│ │ │ │ ├── cardinality: 1.000 +│ │ │ │ ├── precise cardinality: N/A +│ │ │ │ ├── statistics +│ │ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ │ │ └── Scan +│ │ │ │ ├── table: testdb.t +│ │ │ │ ├── filters: [eq(t.a (#0), 1)] +│ │ │ │ ├── order by: [] +│ │ │ │ ├── limit: NONE +│ │ │ │ ├── output columns: [testdb.t.a, testdb.t.b] +│ │ │ │ ├── outer columns: [] +│ │ │ │ ├── used columns: [testdb.t.a, testdb.t.b] +│ │ │ │ ├── cardinality: 1000.000 +│ │ │ │ ├── precise cardinality: 1000 +│ │ │ │ └── statistics +│ │ │ │ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } +│ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } +│ │ │ └── Filter +│ │ │ ├── filters: [eq(t1.a (#2), 1)] +│ │ │ ├── output columns: [testdb.t.a, testdb.t.b] +│ │ │ ├── outer columns: [] +│ │ │ ├── used columns: [testdb.t.a, testdb.t.b] +│ │ │ ├── cardinality: 1.000 +│ │ │ ├── precise cardinality: N/A +│ │ │ ├── statistics +│ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ │ └── Scan +│ │ │ ├── table: testdb.t +│ │ │ ├── filters: [eq(t.a (#2), 1)] +│ │ │ ├── order by: [] +│ │ │ ├── limit: NONE +│ │ │ ├── output columns: [testdb.t.a, testdb.t.b] +│ │ │ ├── outer columns: [] +│ │ │ ├── used columns: [testdb.t.a, testdb.t.b] +│ │ │ ├── cardinality: 1000.000 +│ │ │ ├── precise cardinality: 1000 +│ │ │ └── statistics +│ │ │ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } +│ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } +│ │ └── Filter +│ │ ├── filters: [eq(t2.a (#4), 1)] +│ │ ├── output columns: [testdb.t.a, testdb.t.b] +│ │ ├── outer columns: [] +│ │ ├── used columns: [testdb.t.a, testdb.t.b] +│ │ ├── cardinality: 1.000 +│ │ ├── precise cardinality: N/A +│ │ ├── statistics +│ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ │ └── Scan +│ │ ├── table: testdb.t +│ │ ├── filters: [eq(t.a (#4), 1)] +│ │ ├── order by: [] +│ │ ├── limit: NONE +│ │ ├── output columns: [testdb.t.a, testdb.t.b] +│ │ ├── outer columns: [] +│ │ ├── used columns: [testdb.t.a, testdb.t.b] +│ │ ├── cardinality: 1000.000 +│ │ ├── precise cardinality: 1000 +│ │ └── statistics +│ │ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } +│ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } +│ └── Filter +│ ├── filters: [eq(t3.a (#6), 1)] +│ ├── output columns: [testdb.t.a, testdb.t.b] +│ ├── outer columns: [] +│ ├── used columns: [testdb.t.a, testdb.t.b] +│ ├── cardinality: 1.000 +│ ├── precise cardinality: N/A +│ ├── statistics +│ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } +│ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } +│ └── Scan +│ ├── table: testdb.t +│ ├── filters: [eq(t.a (#6), 1)] +│ ├── order by: [] +│ ├── limit: NONE +│ ├── output columns: [testdb.t.a, testdb.t.b] +│ ├── outer columns: [] +│ ├── used columns: [testdb.t.a, testdb.t.b] +│ ├── cardinality: 1000.000 +│ ├── precise cardinality: 1000 +│ └── statistics +│ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } +│ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } +└── Filter + ├── filters: [eq(t4.a (#8), 1)] + ├── output columns: [testdb.t.a, testdb.t.b] ├── outer columns: [] - ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] + ├── used columns: [testdb.t.a, testdb.t.b] ├── cardinality: 1.000 ├── precise cardinality: N/A ├── statistics │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - ├── Join(Cross) - │ ├── build keys: [] - │ ├── probe keys: [] - │ ├── other filters: [] - │ ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] - │ ├── outer columns: [] - │ ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b, testdb.t.b] - │ ├── cardinality: 1.000 - │ ├── precise cardinality: N/A - │ ├── statistics - │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ ├── Join(Cross) - │ │ ├── build keys: [] - │ │ ├── probe keys: [] - │ │ ├── other filters: [] - │ │ ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b] - │ │ ├── outer columns: [] - │ │ ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b, testdb.t.b] - │ │ ├── cardinality: 1.000 - │ │ ├── precise cardinality: N/A - │ │ ├── statistics - │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ ├── Join(Cross) - │ │ │ ├── build keys: [] - │ │ │ ├── probe keys: [] - │ │ │ ├── other filters: [] - │ │ │ ├── output columns: [testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b] - │ │ │ ├── outer columns: [] - │ │ │ ├── used columns: [testdb.t.a, testdb.t.a, testdb.t.b, testdb.t.b] - │ │ │ ├── cardinality: 1.000 - │ │ │ ├── precise cardinality: N/A - │ │ │ ├── statistics - │ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ │ ├── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ │ ├── Filter - │ │ │ │ ├── filters: [eq(t.a (#0), 1)] - │ │ │ │ ├── output columns: [testdb.t.a, testdb.t.b] - │ │ │ │ ├── outer columns: [] - │ │ │ │ ├── used columns: [testdb.t.a, testdb.t.b] - │ │ │ │ ├── cardinality: 1.000 - │ │ │ │ ├── precise cardinality: N/A - │ │ │ │ ├── statistics - │ │ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ │ │ └── Scan - │ │ │ │ ├── table: testdb.t - │ │ │ │ ├── filters: [eq(t.a (#0), 1)] - │ │ │ │ ├── order by: [] - │ │ │ │ ├── limit: NONE - │ │ │ │ ├── output columns: [testdb.t.a, testdb.t.b] - │ │ │ │ ├── outer columns: [] - │ │ │ │ ├── used columns: [testdb.t.a, testdb.t.b] - │ │ │ │ ├── cardinality: 1000.000 - │ │ │ │ ├── precise cardinality: 1000 - │ │ │ │ └── statistics - │ │ │ │ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } - │ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } - │ │ │ └── Filter - │ │ │ ├── filters: [eq(t1.a (#2), 1)] - │ │ │ ├── output columns: [testdb.t.a, testdb.t.b] - │ │ │ ├── outer columns: [] - │ │ │ ├── used columns: [testdb.t.a, testdb.t.b] - │ │ │ ├── cardinality: 1.000 - │ │ │ ├── precise cardinality: N/A - │ │ │ ├── statistics - │ │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ │ └── Scan - │ │ │ ├── table: testdb.t - │ │ │ ├── filters: [eq(t.a (#2), 1)] - │ │ │ ├── order by: [] - │ │ │ ├── limit: NONE - │ │ │ ├── output columns: [testdb.t.a, testdb.t.b] - │ │ │ ├── outer columns: [] - │ │ │ ├── used columns: [testdb.t.a, testdb.t.b] - │ │ │ ├── cardinality: 1000.000 - │ │ │ ├── precise cardinality: 1000 - │ │ │ └── statistics - │ │ │ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } - │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } - │ │ └── Filter - │ │ ├── filters: [eq(t2.a (#4), 1)] - │ │ ├── output columns: [testdb.t.a, testdb.t.b] - │ │ ├── outer columns: [] - │ │ ├── used columns: [testdb.t.a, testdb.t.b] - │ │ ├── cardinality: 1.000 - │ │ ├── precise cardinality: N/A - │ │ ├── statistics - │ │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ │ └── Scan - │ │ ├── table: testdb.t - │ │ ├── filters: [eq(t.a (#4), 1)] - │ │ ├── order by: [] - │ │ ├── limit: NONE - │ │ ├── output columns: [testdb.t.a, testdb.t.b] - │ │ ├── outer columns: [] - │ │ ├── used columns: [testdb.t.a, testdb.t.b] - │ │ ├── cardinality: 1000.000 - │ │ ├── precise cardinality: 1000 - │ │ └── statistics - │ │ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } - │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } - │ └── Filter - │ ├── filters: [eq(t3.a (#6), 1)] - │ ├── output columns: [testdb.t.a, testdb.t.b] - │ ├── outer columns: [] - │ ├── used columns: [testdb.t.a, testdb.t.b] - │ ├── cardinality: 1.000 - │ ├── precise cardinality: N/A - │ ├── statistics - │ │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - │ └── Scan - │ ├── table: testdb.t - │ ├── filters: [eq(t.a (#6), 1)] - │ ├── order by: [] - │ ├── limit: NONE - │ ├── output columns: [testdb.t.a, testdb.t.b] - │ ├── outer columns: [] - │ ├── used columns: [testdb.t.a, testdb.t.b] - │ ├── cardinality: 1000.000 - │ ├── precise cardinality: 1000 - │ └── statistics - │ ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } - │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } - └── Filter - ├── filters: [eq(t4.a (#8), 1)] + └── Scan + ├── table: testdb.t + ├── filters: [eq(t.a (#8), 1)] + ├── order by: [] + ├── limit: NONE ├── output columns: [testdb.t.a, testdb.t.b] ├── outer columns: [] ├── used columns: [testdb.t.a, testdb.t.b] - ├── cardinality: 1.000 - ├── precise cardinality: N/A - ├── statistics - │ ├── testdb.t.a: { min: 1, max: 1, ndv: 1, null count: 0 } - │ └── testdb.t.b: { min: 1, max: 1000, ndv: 1, null count: 0 } - └── Scan - ├── table: testdb.t - ├── filters: [eq(t.a (#8), 1)] - ├── order by: [] - ├── limit: NONE - ├── output columns: [testdb.t.a, testdb.t.b] - ├── outer columns: [] - ├── used columns: [testdb.t.a, testdb.t.b] - ├── cardinality: 1000.000 - ├── precise cardinality: 1000 - └── statistics - ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } - └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } + ├── cardinality: 1000.000 + ├── precise cardinality: 1000 + └── statistics + ├── testdb.t.a: { min: 0, max: 999, ndv: 1000, null count: 0 } + └── testdb.t.b: { min: 1, max: 1000, ndv: 1000, null count: 0 } statement ok drop database testdb diff --git a/tests/sqllogictests/suites/mode/standalone/explain/insert.test b/tests/sqllogictests/suites/mode/standalone/explain/insert.test index ec12716969d2..58ebfcaa4b56 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/insert.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/insert.test @@ -25,15 +25,13 @@ InsertPlan (subquery): ├── table: default.default.t2 ├── inserted columns: [t2.a (#0),t2.b (#1)] ├── overwrite: false -└── EvalScalar - ├── scalars: [t1.a (#0) AS (#0), t1.b (#1) AS (#1)] - └── Filter +└── Filter + ├── filters: [eq(t1.a (#0), 1)] + └── Scan + ├── table: default.t1 ├── filters: [eq(t1.a (#0), 1)] - └── Scan - ├── table: default.t1 - ├── filters: [eq(t1.a (#0), 1)] - ├── order by: [] - └── limit: NONE + ├── order by: [] + └── limit: NONE diff --git a/tests/sqllogictests/suites/mode/standalone/explain/lazy_read.test b/tests/sqllogictests/suites/mode/standalone/explain/lazy_read.test index c9331d9d1273..5f6ef467e377 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/lazy_read.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/lazy_read.test @@ -97,7 +97,7 @@ RowFetch ├── estimated rows: 0.00 └── Filter ├── output columns: [t_11831.uid (#0), t_11831.time (#3), t_11831._row_id (#4)] - ├── filters: [is_true(t_11831.time (#3) >= 1686672000000), is_true(t_11831.time (#3) <= 1686758399000), is_true(t_11831.uid (#0) = 11)] + ├── filters: [is_true(t1.time (#3) >= 1686672000000), is_true(t1.time (#3) <= 1686758399000), is_true(t1.uid (#0) = 11)] ├── estimated rows: 0.00 └── TableScan ├── table: default.default.t_11831 @@ -210,7 +210,7 @@ Limit └── estimated rows: 0.00 # Will use lazy materialization -query T +query ? explain with cte as (select a, a + 1 as X, b + 1 as Y from t_lazy order by a limit 3) select X,Y,a from (select * from cte order by Y limit 2) order by X limit 1; ---- Limit diff --git a/tests/sqllogictests/suites/mode/standalone/explain/push_down_filter/push_down_filter_join/push_down_filter_self_join.test b/tests/sqllogictests/suites/mode/standalone/explain/push_down_filter/push_down_filter_join/push_down_filter_self_join.test index 5d9c6c0db4ff..ff198237bf8a 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/push_down_filter/push_down_filter_join/push_down_filter_self_join.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/push_down_filter/push_down_filter_join/push_down_filter_self_join.test @@ -42,10 +42,10 @@ MaterializedCTE ├── build keys: [b2.a (#6)] ├── probe keys: [b1.a (#4)] ├── filters: [b1.b (#5) < b2.b (#7)] - ├── estimated rows: 100.00 + ├── estimated rows: 400.00 ├── CTEScan(Build) │ ├── CTE index: 0, sub index: 2 - │ └── estimated rows: 10.00 + │ └── estimated rows: 20.00 └── CTEScan(Probe) ├── CTE index: 0, sub index: 1 - └── estimated rows: 10.00 + └── estimated rows: 20.00 diff --git a/tests/sqllogictests/suites/mode/standalone/explain/sort.test b/tests/sqllogictests/suites/mode/standalone/explain/sort.test index e08c72e02bc2..5e3a47907db0 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/sort.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/sort.test @@ -10,7 +10,7 @@ Sort ├── estimated rows: 0.00 └── Filter ├── output columns: [t1.a (#0)] - ├── filters: [is_true(t2.a (#0) > 1)] + ├── filters: [is_true(t1.a (#0) > 1)] ├── estimated rows: 0.00 └── TableScan ├── table: default.default.t1 @@ -52,7 +52,7 @@ Sort ├── estimated rows: 0.00 └── Filter ├── output columns: [t1.a (#0)] - ├── filters: [is_true(t1.a (#0) > 1)] + ├── filters: [is_true(t2.a (#0) > 1)] ├── estimated rows: 0.00 └── TableScan ├── table: default.default.t1 diff --git a/tests/sqllogictests/suites/mode/standalone/explain/window.test b/tests/sqllogictests/suites/mode/standalone/explain/window.test index f6fd9d089ef4..2d853bc8087f 100644 --- a/tests/sqllogictests/suites/mode/standalone/explain/window.test +++ b/tests/sqllogictests/suites/mode/standalone/explain/window.test @@ -554,16 +554,15 @@ explain pipeline select *,lead(number,1, 42) over (order by number), lead(numbe ---- CompoundBlockOperator(Project) × 1 Transform Window × 1 - CompoundBlockOperator(Map) × 1 - Transform Window × 1 - CompoundBlockOperator(Map) × 1 - Transform Window × 1 - Merge to MultiSortMerge × 1 - TransformSortMerge × 4 - SortPartialTransform × 4 - Merge to Resize × 4 - CompoundBlockOperator(Map) × 1 - NumbersSourceTransform × 1 + Transform Window × 1 + CompoundBlockOperator(Map) × 1 + Transform Window × 1 + Merge to MultiSortMerge × 1 + TransformSortMerge × 4 + SortPartialTransform × 4 + Merge to Resize × 4 + CompoundBlockOperator(Map) × 1 + NumbersSourceTransform × 1 # same order same partiton by multi window query T @@ -571,15 +570,14 @@ explain pipeline select number, lead(number,1, 0) over (partition by number % 3 ---- CompoundBlockOperator(Project) × 1 Transform Window × 1 - CompoundBlockOperator(Map) × 1 - Transform Window × 1 - TransformWindowPartitionSort × 1 - TransformWindowPartitionSpillReader × 1 - TransformWindowPartitionBucket × 1 - TransformWindowPartitionSpillWriter × 1 - TransformWindowPartitionScatter × 1 - CompoundBlockOperator(Map) × 1 - NumbersSourceTransform × 1 + Transform Window × 1 + TransformWindowPartitionSort × 1 + TransformWindowPartitionSpillReader × 1 + TransformWindowPartitionBucket × 1 + TransformWindowPartitionSpillWriter × 1 + TransformWindowPartitionScatter × 1 + CompoundBlockOperator(Map) × 1 + NumbersSourceTransform × 1 # window partition with empty sort items from same window partition with sort items ## explain select a, sum(number - 1) over (partition by number % 3) from (select number, rank()over (partition by number % 3 order by number + 1) a @@ -627,48 +625,40 @@ explain select number, avg(number) over (partition by number % 3), rank() over from numbers(50); ---- Window -├── output columns: [numbers.number (#0), avg_part_0 (#1), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), avg(number) OVER ( PARTITION BY number % 3 ) (#2), avg_part_0 (#1), sum(number) OVER ( PARTITION BY number % 3 ) (#5)] +├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), avg(number) OVER ( PARTITION BY number % 3 ) (#2), sum(number) OVER ( PARTITION BY number % 3 ) (#5)] ├── aggregate function: [sum(number)] ├── partition by: [avg_part_0] ├── order by: [] ├── frame: [Range: Preceding(None) ~ Following(None)] -└── EvalScalar - ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), avg(number) OVER ( PARTITION BY number % 3 ) (#2), avg_part_0 (#1)] - ├── expressions: [numbers.number (#0) % 3] - ├── estimated rows: 50.00 +└── Window + ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), avg(number) OVER ( PARTITION BY number % 3 ) (#2)] + ├── aggregate function: [avg(number)] + ├── partition by: [avg_part_0] + ├── order by: [] + ├── frame: [Range: Preceding(None) ~ Following(None)] └── Window - ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), avg_part_0 (#1), avg(number) OVER ( PARTITION BY number % 3 ) (#2)] - ├── aggregate function: [avg(number)] + ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4)] + ├── aggregate function: [rank] ├── partition by: [avg_part_0] - ├── order by: [] - ├── frame: [Range: Preceding(None) ~ Following(None)] - └── EvalScalar - ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4), avg_part_0 (#1)] - ├── expressions: [numbers.number (#0) % 3] + ├── order by: [rank_order_0] + ├── frame: [Range: Preceding(None) ~ CurrentRow] + └── WindowPartition + ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3)] + ├── hash keys: [avg_part_0] ├── estimated rows: 50.00 - └── Window - ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3), rank() OVER ( PARTITION BY number % 3 ORDER BY number + 1 ) (#4)] - ├── aggregate function: [rank] - ├── partition by: [avg_part_0] - ├── order by: [rank_order_0] - ├── frame: [Range: Preceding(None) ~ CurrentRow] - └── WindowPartition - ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3)] - ├── hash keys: [avg_part_0] - ├── estimated rows: 50.00 - └── EvalScalar - ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3)] - ├── expressions: [numbers.number (#0) % 3, numbers.number (#0) + 1] - ├── estimated rows: 50.00 - └── TableScan - ├── table: default.system.numbers - ├── output columns: [number (#0)] - ├── read rows: 50 - ├── read size: < 1 KiB - ├── partitions total: 1 - ├── partitions scanned: 1 - ├── push downs: [filters: [], limit: NONE] - └── estimated rows: 50.00 + └── EvalScalar + ├── output columns: [numbers.number (#0), avg_part_0 (#1), rank_order_0 (#3)] + ├── expressions: [numbers.number (#0) % 3, numbers.number (#0) + 1] + ├── estimated rows: 50.00 + └── TableScan + ├── table: default.system.numbers + ├── output columns: [number (#0)] + ├── read rows: 50 + ├── read size: < 1 KiB + ├── partitions total: 1 + ├── partitions scanned: 1 + ├── push downs: [filters: [], limit: NONE] + └── estimated rows: 50.00 query T explain select a, sum(number - 1) over (partition by number % 3) from (select number, rank()over (partition by number % 3 order by number) a from numbers(50)); diff --git a/tests/sqllogictests/suites/query/subquery.test b/tests/sqllogictests/suites/query/subquery.test index 16275f11aedb..379c6d5c475d 100644 --- a/tests/sqllogictests/suites/query/subquery.test +++ b/tests/sqllogictests/suites/query/subquery.test @@ -244,14 +244,14 @@ SELECT * FROM c WHERE (SELECT count(*) FROM o WHERE o.c_id=c.c_id) > 1 ORDER BY 4 TX -query IT +query ?? SELECT * FROM c WHERE (SELECT count(ship) FROM o WHERE o.c_id=c.c_id) > 1 ORDER BY c_id ---- -1 CA -2 TX +1 CA +2 TX -query IT +query ?? SELECT * FROM c WHERE @@ -259,7 +259,7 @@ WHERE AND (SELECT max(ship) FROM o WHERE o.c_id=c.c_id) = 'CA' ORDER BY c_id ---- -1 CA +1 CA query IT @@ -546,11 +546,11 @@ ORDER BY c.c_id, o.o_id 2 40 TX 2 50 TX 2 60 TX +3 NULL NULL 4 70 WY 4 80 WY -6 90 WA -3 NULL NULL 5 NULL NULL +6 90 WA query II @@ -562,10 +562,10 @@ ORDER BY c_id ---- 1 3 2 3 -4 2 -6 1 3 0 +4 2 5 0 +6 1 query I @@ -817,7 +817,7 @@ CREATE TABLE `merge_log` ( `created_at` TIMESTAMP NULL ) ENGINE = FUSE; -query +query SELECT (SELECT MAX(created_at) FROM merge_log