diff --git a/Cargo.lock b/Cargo.lock index f0ea1893..1a48d830 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2780,6 +2780,7 @@ dependencies = [ "itertools", "optd-core", "optd-datafusion-repr", + "tracing", ] [[package]] diff --git a/optd-datafusion-bridge/Cargo.toml b/optd-datafusion-bridge/Cargo.toml index 9c4edf46..b52c12d0 100644 --- a/optd-datafusion-bridge/Cargo.toml +++ b/optd-datafusion-bridge/Cargo.toml @@ -16,3 +16,4 @@ async-recursion = "1" futures-lite = "2" futures-util = "0.3" itertools = "0.11" +tracing = "0.1" diff --git a/optd-datafusion-bridge/src/lib.rs b/optd-datafusion-bridge/src/lib.rs index 1f4d3724..7cde649e 100644 --- a/optd-datafusion-bridge/src/lib.rs +++ b/optd-datafusion-bridge/src/lib.rs @@ -132,6 +132,7 @@ impl OptdQueryPlanner { })); } let mut optd_rel = ctx.conv_into_optd(logical_plan)?; + if let Some(explains) = &mut explains { explains.push(StringifiedPlan::new( PlanType::OptimizedLogicalPlan { @@ -142,9 +143,17 @@ impl OptdQueryPlanner { .explain_to_string(None), )); } + + tracing::trace!( + optd_unoptimized_plan = %("\n".to_string() + + &PlanNode::from_rel_node(optd_rel.clone()) + .unwrap() + .explain_to_string(None))); + let mut optimizer = self.optimizer.lock().unwrap().take().unwrap(); if optimizer.is_heuristic_enabled() { + // TODO: depjoin pushdown might need to run multiple times optd_rel = optimizer.heuristic_optimize(optd_rel); if let Some(explains) = &mut explains { explains.push(StringifiedPlan::new( @@ -156,6 +165,11 @@ impl OptdQueryPlanner { .explain_to_string(None), )) } + tracing::trace!( + optd_optimized_plan = %("\n".to_string() + + &PlanNode::from_rel_node(optd_rel.clone()) + .unwrap() + .explain_to_string(None))); } let (group_id, optimized_rel, meta) = optimizer.cascades_optimize(optd_rel)?; @@ -180,6 +194,13 @@ impl OptdQueryPlanner { join_orders.iter().map(|x| x.to_string()).join("\n"), )); } + + tracing::trace!( + optd_physical_plan = %("\n".to_string() + + &PlanNode::from_rel_node(optimized_rel.clone()) + .unwrap() + .explain_to_string(None))); + ctx.optimizer = Some(&optimizer); let physical_plan = ctx.conv_from_optd(optimized_rel, meta).await?; if let Some(explains) = &mut explains { diff --git a/optd-datafusion-repr/src/lib.rs b/optd-datafusion-repr/src/lib.rs index 0df8efe7..952b898a 100644 --- a/optd-datafusion-repr/src/lib.rs +++ b/optd-datafusion-repr/src/lib.rs @@ -31,7 +31,7 @@ use rules::{ pub use optd_core::rel_node::Value; use crate::rules::{ - DepInitialDistinct, DepJoinEliminateAtScan, DepJoinPastAgg, DepJoinPastFilter, DepJoinPastProj, + DepInitialDistinct, DepJoinEliminate, DepJoinPastAgg, DepJoinPastFilter, DepJoinPastProj, }; pub use memo_ext::{LogicalJoinOrder, MemoExt}; @@ -93,7 +93,7 @@ impl DatafusionOptimizer { Arc::new(EliminateLimitRule::new()), Arc::new(EliminateDuplicatedSortExprRule::new()), Arc::new(EliminateDuplicatedAggExprRule::new()), - Arc::new(DepJoinEliminateAtScan::new()), + Arc::new(DepJoinEliminate::new()), Arc::new(DepInitialDistinct::new()), Arc::new(DepJoinPastProj::new()), Arc::new(DepJoinPastFilter::new()), diff --git a/optd-datafusion-repr/src/rules.rs b/optd-datafusion-repr/src/rules.rs index c06a46e2..f51028f2 100644 --- a/optd-datafusion-repr/src/rules.rs +++ b/optd-datafusion-repr/src/rules.rs @@ -27,5 +27,5 @@ pub use project_transpose::{ project_merge::{EliminateProjectRule, ProjectMergeRule}, }; pub use subquery::{ - DepInitialDistinct, DepJoinEliminateAtScan, DepJoinPastAgg, DepJoinPastFilter, DepJoinPastProj, + DepInitialDistinct, DepJoinEliminate, DepJoinPastAgg, DepJoinPastFilter, DepJoinPastProj, }; diff --git a/optd-datafusion-repr/src/rules/subquery.rs b/optd-datafusion-repr/src/rules/subquery.rs index 70aece04..b6e0bf84 100644 --- a/optd-datafusion-repr/src/rules/subquery.rs +++ b/optd-datafusion-repr/src/rules/subquery.rs @@ -1,5 +1,5 @@ pub mod depjoin_pushdown; pub use depjoin_pushdown::{ - DepInitialDistinct, DepJoinEliminateAtScan, DepJoinPastAgg, DepJoinPastFilter, DepJoinPastProj, + DepInitialDistinct, DepJoinEliminate, DepJoinPastAgg, DepJoinPastFilter, DepJoinPastProj, }; diff --git a/optd-datafusion-repr/src/rules/subquery/depjoin_pushdown.rs b/optd-datafusion-repr/src/rules/subquery/depjoin_pushdown.rs index cdea456c..c7f9f1d2 100644 --- a/optd-datafusion-repr/src/rules/subquery/depjoin_pushdown.rs +++ b/optd-datafusion-repr/src/rules/subquery/depjoin_pushdown.rs @@ -418,8 +418,10 @@ fn apply_dep_join_past_agg( vec![new_agg.into_rel_node().as_ref().clone()] } +// Heuristics-only rule. If we don't have references to the external columns on the right side, +// we can rewrite the dependent join into a normal join. define_rule!( - DepJoinEliminateAtScan, + DepJoinEliminate, apply_dep_join_eliminate_at_scan, // TODO matching is all wrong (DepJoin(JoinType::Cross), left, right, [cond], [extern_cols]) ); @@ -428,31 +430,40 @@ define_rule!( /// for an inner join! Our main mission is complete! fn apply_dep_join_eliminate_at_scan( _optimizer: &impl Optimizer, - DepJoinEliminateAtScanPicks { + DepJoinEliminatePicks { left, right, cond, extern_cols: _, - }: DepJoinEliminateAtScanPicks, + }: DepJoinEliminatePicks, ) -> Vec> { - // TODO: Is there ever a situation we need to detect that we can convert earlier? - // Technically we can convert as soon as we clear the last externcolumnref... - // Cross join should always have true cond assert!(cond == *ConstantExpr::bool(true).into_rel_node()); - if right.typ != OptRelNodeTyp::Scan { - return vec![]; + fn inspect(node: &RelNode) -> bool { + if matches!(node.typ, OptRelNodeTyp::Placeholder(_)) { + unimplemented!("this is a heuristics rule"); + } + if node.typ == OptRelNodeTyp::ExternColumnRef { + return false; + } + for child in &node.children { + if !inspect(child) { + return false; + } + } + true } - // let scan = LogicalScan::new("test".to_string()).into_rel_node(); - - let new_join = LogicalJoin::new( - PlanNode::from_group(left.into()), - PlanNode::from_group(right.into()), - ConstantExpr::bool(true).into_expr(), - JoinType::Inner, - ); - - vec![new_join.into_rel_node().as_ref().clone()] + if inspect(&right) { + let new_join = LogicalJoin::new( + PlanNode::from_group(left.into()), + PlanNode::from_group(right.into()), + ConstantExpr::bool(true).into_expr(), + JoinType::Inner, + ); + vec![new_join.into_rel_node().as_ref().clone()] + } else { + vec![] + } } diff --git a/optd-sqlplannertest/README.md b/optd-sqlplannertest/README.md index 6946fe30..b582566d 100644 --- a/optd-sqlplannertest/README.md +++ b/optd-sqlplannertest/README.md @@ -51,5 +51,5 @@ Currently we have the following options for the explain task: ## Tracing a query ``` -RUST_LOG=optd_core=trace cargo run -p optd-sqlplannertest --bin planner_test_apply -- pushdowns &> log +RUST_BACKTRACE=1 RUST_LOG=optd_core=trace,optd_datafusion_bridge=trace cargo run -p optd-sqlplannertest --bin planner_test_apply -- pushdowns &> log ``` diff --git a/optd-sqlplannertest/tests/subqueries/subquery_unnesting.planner.sql b/optd-sqlplannertest/tests/subqueries/subquery_unnesting.planner.sql index dceb756d..5fa76831 100644 --- a/optd-sqlplannertest/tests/subqueries/subquery_unnesting.planner.sql +++ b/optd-sqlplannertest/tests/subqueries/subquery_unnesting.planner.sql @@ -75,3 +75,87 @@ PhysicalProjection { exprs: [ #2, #3 ], cost: {compute=9147.220000000001,io=3000 └── PhysicalScan { table: t1, cost: {compute=0,io=1000}, stat: {row_cnt=1000} } */ +-- Test whether the optimizer can unnest correlated subqueries. +select * from t1 where (select sum(t2v3) from (select * from t2, t3 where t2v1 = t1v1 and t2v3 = t3v2)) > 100; + +/* +LogicalProjection { exprs: [ #0, #1 ] } +└── LogicalFilter + ├── cond:Gt + │ ├── #2 + │ └── 100(i64) + └── RawDependentJoin { join_type: Cross, cond: true, extern_cols: [ Extern(#0) ] } + ├── LogicalScan { table: t1 } + └── LogicalProjection { exprs: [ #0 ] } + └── LogicalAgg + ├── exprs:Agg(Sum) + │ └── [ Cast { cast_to: Int64, expr: #1 } ] + ├── groups: [] + └── LogicalProjection { exprs: [ #0, #1, #2, #3 ] } + └── LogicalFilter + ├── cond:And + │ ├── Eq + │ │ ├── #0 + │ │ └── Extern(#0) + │ └── Eq + │ ├── #1 + │ └── #2 + └── LogicalJoin { join_type: Cross, cond: true } + ├── LogicalScan { table: t2 } + └── LogicalScan { table: t3 } +LogicalProjection { exprs: [ #0, #1 ] } +└── LogicalFilter + ├── cond:Gt + │ ├── #2 + │ └── 100(i64) + └── LogicalProjection { exprs: [ #0, #1, #3 ] } + └── LogicalJoin + ├── join_type: Inner + ├── cond:Eq + │ ├── #0 + │ └── #2 + ├── LogicalScan { table: t1 } + └── LogicalProjection { exprs: [ #0, #1 ] } + └── LogicalAgg + ├── exprs:Agg(Sum) + │ └── [ Cast { cast_to: Int64, expr: #2 } ] + ├── groups: [ #1 ] + └── LogicalProjection { exprs: [ #0, #1, #2, #3, #4 ] } + └── LogicalFilter + ├── cond:And + │ ├── Eq + │ │ ├── #1 + │ │ └── #0 + │ └── Eq + │ ├── #2 + │ └── #3 + └── LogicalJoin { join_type: Inner, cond: true } + ├── LogicalAgg { exprs: [], groups: [ #0 ] } + │ └── LogicalScan { table: t1 } + └── LogicalJoin { join_type: Cross, cond: true } + ├── LogicalScan { table: t2 } + └── LogicalScan { table: t3 } +PhysicalProjection { exprs: [ #2, #3 ], cost: {compute=10153.240000000002,io=4000}, stat: {row_cnt=1} } +└── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ], cost: {compute=10145.220000000001,io=4000}, stat: {row_cnt=1} } + ├── PhysicalAgg + │ ├── aggrs:Agg(Sum) + │ │ └── [ Cast { cast_to: Int64, expr: #2 } ] + │ ├── groups: [ #1 ] + │ ├── cost: {compute=9139.2,io=3000} + │ ├── stat: {row_cnt=1} + │ └── PhysicalHashJoin { join_type: Inner, left_keys: [ #2 ], right_keys: [ #0 ], cost: {compute=9051.080000000002,io=3000}, stat: {row_cnt=1} } + │ ├── PhysicalProjection { exprs: [ #2, #0, #1 ], cost: {compute=8045.06,io=2000}, stat: {row_cnt=1} } + │ │ └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ], cost: {compute=8033.04,io=2000}, stat: {row_cnt=1} } + │ │ ├── PhysicalFilter + │ │ │ ├── cond:Gt + │ │ │ │ ├── #0 + │ │ │ │ └── 100(i64) + │ │ │ ├── cost: {compute=5005,io=1000} + │ │ │ ├── stat: {row_cnt=1} + │ │ │ └── PhysicalScan { table: t2, cost: {compute=0,io=1000}, stat: {row_cnt=1000} } + │ │ └── PhysicalAgg { aggrs: [], groups: [ #0 ], cost: {compute=2022.0199999999995,io=1000}, stat: {row_cnt=1000} } + │ │ └── PhysicalScan { table: t1, cost: {compute=0,io=1000}, stat: {row_cnt=1000} } + │ └── PhysicalScan { table: t3, cost: {compute=0,io=1000}, stat: {row_cnt=1000} } + └── PhysicalScan { table: t1, cost: {compute=0,io=1000}, stat: {row_cnt=1000} } +*/ + diff --git a/optd-sqlplannertest/tests/subqueries/subquery_unnesting.yml b/optd-sqlplannertest/tests/subqueries/subquery_unnesting.yml index 8d5d574a..fc1303e4 100644 --- a/optd-sqlplannertest/tests/subqueries/subquery_unnesting.yml +++ b/optd-sqlplannertest/tests/subqueries/subquery_unnesting.yml @@ -14,3 +14,8 @@ desc: Test whether the optimizer can unnest correlated subqueries. tasks: - explain[verbose]:logical_optd,optimized_logical_optd,physical_optd +- sql: | + select * from t1 where (select sum(t2v3) from (select * from t2, t3 where t2v1 = t1v1 and t2v3 = t3v2)) > 100; + desc: Test whether the optimizer can unnest correlated subqueries. + tasks: + - explain[verbose]:logical_optd,optimized_logical_optd,physical_optd diff --git a/optd-sqlplannertest/tests/tpch/tpch-01-05.planner.sql b/optd-sqlplannertest/tests/tpch/tpch-01-05.planner.sql index b6e1ab35..2dab0be5 100644 --- a/optd-sqlplannertest/tests/tpch/tpch-01-05.planner.sql +++ b/optd-sqlplannertest/tests/tpch/tpch-01-05.planner.sql @@ -259,98 +259,70 @@ LogicalLimit { skip: 0(u64), fetch: 100(u64) } │ │ └── #1 │ └── SortOrder { order: Asc } │ └── #3 - └── LogicalProjection { exprs: [ #5, #2, #8, #0, #1, #3, #4, #6 ] } - └── LogicalJoin - ├── join_type: Inner + └── LogicalProjection { exprs: [ #14, #10, #22, #0, #2, #11, #13, #15 ] } + └── LogicalFilter ├── cond:And │ ├── Eq │ │ ├── #0 - │ │ └── #10 + │ │ └── #16 + │ ├── Eq + │ │ ├── #9 + │ │ └── #17 + │ ├── Eq + │ │ ├── Cast { cast_to: Int64, expr: #5 } + │ │ └── 4(i64) + │ ├── Like { expr: #4, pattern: "%TIN", negated: false, case_insensitive: false } + │ ├── Eq + │ │ ├── #12 + │ │ └── #21 + │ ├── Eq + │ │ ├── #23 + │ │ └── #25 + │ ├── Eq + │ │ ├── #26 + │ │ └── "AFRICA" │ └── Eq - │ ├── #7 - │ └── #9 - ├── LogicalProjection { exprs: [ #0, #1, #2, #3, #4, #5, #6, #7, #8 ] } - │ └── LogicalJoin - │ ├── join_type: Inner - │ ├── cond:Eq - │ │ ├── #9 - │ │ └── #10 - │ ├── LogicalProjection { exprs: [ #0, #1, #2, #3, #5, #6, #7, #8, #10, #11 ] } - │ │ └── LogicalJoin - │ │ ├── join_type: Inner - │ │ ├── cond:Eq - │ │ │ ├── #4 - │ │ │ └── #9 - │ │ ├── LogicalProjection { exprs: [ #0, #1, #5, #6, #7, #8, #9, #10, #3 ] } - │ │ │ └── LogicalJoin - │ │ │ ├── join_type: Inner - │ │ │ ├── cond:Eq - │ │ │ │ ├── #2 - │ │ │ │ └── #4 - │ │ │ ├── LogicalProjection { exprs: [ #0, #1, #3, #4 ] } - │ │ │ │ └── LogicalJoin - │ │ │ │ ├── join_type: Inner - │ │ │ │ ├── cond:Eq - │ │ │ │ │ ├── #0 - │ │ │ │ │ └── #2 - │ │ │ │ ├── LogicalProjection { exprs: [ #0, #1 ] } - │ │ │ │ │ └── LogicalFilter - │ │ │ │ │ ├── cond:And - │ │ │ │ │ │ ├── Eq - │ │ │ │ │ │ │ ├── #3 - │ │ │ │ │ │ │ └── 4(i32) - │ │ │ │ │ │ └── Like { expr: #2, pattern: "%TIN", negated: false, case_insensitive: false } - │ │ │ │ │ └── LogicalProjection { exprs: [ #0, #2, #4, #5 ] } - │ │ │ │ │ └── LogicalScan { table: part } - │ │ │ │ └── LogicalProjection { exprs: [ #0, #1, #3 ] } - │ │ │ │ └── LogicalScan { table: partsupp } - │ │ │ └── LogicalProjection { exprs: [ #0, #1, #2, #3, #4, #5, #6 ] } - │ │ │ └── LogicalScan { table: supplier } - │ │ └── LogicalProjection { exprs: [ #0, #1, #2 ] } - │ │ └── LogicalScan { table: nation } - │ └── LogicalProjection { exprs: [ #0 ] } - │ └── LogicalFilter - │ ├── cond:Eq - │ │ ├── #1 - │ │ └── "AFRICA" - │ └── LogicalProjection { exprs: [ #0, #1 ] } - │ └── LogicalScan { table: region } - └── LogicalProjection { exprs: [ #1, #0 ] } - └── LogicalAgg - ├── exprs:Agg(Min) - │ └── [ #1 ] - ├── groups: [ #0 ] - └── LogicalProjection { exprs: [ #0, #1 ] } - └── LogicalJoin - ├── join_type: Inner - ├── cond:Eq - │ ├── #2 - │ └── #3 - ├── LogicalProjection { exprs: [ #0, #1, #4 ] } - │ └── LogicalJoin - │ ├── join_type: Inner - │ ├── cond:Eq - │ │ ├── #2 - │ │ └── #3 - │ ├── LogicalProjection { exprs: [ #0, #2, #4 ] } - │ │ └── LogicalJoin - │ │ ├── join_type: Inner - │ │ ├── cond:Eq - │ │ │ ├── #1 - │ │ │ └── #3 - │ │ ├── LogicalProjection { exprs: [ #0, #1, #3 ] } - │ │ │ └── LogicalScan { table: partsupp } - │ │ └── LogicalProjection { exprs: [ #0, #3 ] } - │ │ └── LogicalScan { table: supplier } - │ └── LogicalProjection { exprs: [ #0, #2 ] } - │ └── LogicalScan { table: nation } - └── LogicalProjection { exprs: [ #0 ] } - └── LogicalFilter - ├── cond:Eq - │ ├── #1 - │ └── "AFRICA" - └── LogicalProjection { exprs: [ #0, #1 ] } - └── LogicalScan { table: region } + │ ├── #19 + │ └── #28 + └── RawDependentJoin { join_type: Cross, cond: true, extern_cols: [ Extern(#0) ] } + ├── LogicalJoin { join_type: Cross, cond: true } + │ ├── LogicalJoin { join_type: Cross, cond: true } + │ │ ├── LogicalJoin { join_type: Cross, cond: true } + │ │ │ ├── LogicalJoin { join_type: Cross, cond: true } + │ │ │ │ ├── LogicalScan { table: part } + │ │ │ │ └── LogicalScan { table: supplier } + │ │ │ └── LogicalScan { table: partsupp } + │ │ └── LogicalScan { table: nation } + │ └── LogicalScan { table: region } + └── LogicalProjection { exprs: [ #0 ] } + └── LogicalAgg + ├── exprs:Agg(Min) + │ └── [ #3 ] + ├── groups: [] + └── LogicalFilter + ├── cond:And + │ ├── Eq + │ │ ├── Extern(#0) + │ │ └── #0 + │ ├── Eq + │ │ ├── #5 + │ │ └── #1 + │ ├── Eq + │ │ ├── #8 + │ │ └── #12 + │ ├── Eq + │ │ ├── #14 + │ │ └── #16 + │ └── Eq + │ ├── #17 + │ └── "AFRICA" + └── LogicalJoin { join_type: Cross, cond: true } + ├── LogicalJoin { join_type: Cross, cond: true } + │ ├── LogicalJoin { join_type: Cross, cond: true } + │ │ ├── LogicalScan { table: partsupp } + │ │ └── LogicalScan { table: supplier } + │ └── LogicalScan { table: nation } + └── LogicalScan { table: region } PhysicalLimit { skip: 0(u64), fetch: 100(u64) } └── PhysicalSort ├── exprs: @@ -362,52 +334,66 @@ PhysicalLimit { skip: 0(u64), fetch: 100(u64) } │ │ └── #1 │ └── SortOrder { order: Asc } │ └── #3 - └── PhysicalProjection { exprs: [ #19, #15, #22, #0, #2, #16, #18, #20 ] } - └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0, #12 ], right_keys: [ #1, #0 ] } + └── PhysicalProjection { exprs: [ #14, #10, #22, #0, #2, #11, #13, #15 ] } + └── PhysicalHashJoin { join_type: Inner, left_keys: [ #19, #0 ], right_keys: [ #1, #0 ] } ├── PhysicalHashJoin { join_type: Inner, left_keys: [ #23 ], right_keys: [ #0 ] } - │ ├── PhysicalHashJoin { join_type: Inner, left_keys: [ #17 ], right_keys: [ #0 ] } - │ │ ├── PhysicalHashJoin { join_type: Inner, left_keys: [ #10 ], right_keys: [ #0 ] } - │ │ │ ├── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ] } + │ ├── PhysicalHashJoin { join_type: Inner, left_keys: [ #12 ], right_keys: [ #0 ] } + │ │ ├── PhysicalHashJoin { join_type: Inner, left_keys: [ #0, #9 ], right_keys: [ #0, #1 ] } + │ │ │ ├── PhysicalNestedLoopJoin { join_type: Cross, cond: true } │ │ │ │ ├── PhysicalFilter │ │ │ │ │ ├── cond:And │ │ │ │ │ │ ├── Eq - │ │ │ │ │ │ │ ├── #5 - │ │ │ │ │ │ │ └── 4(i32) + │ │ │ │ │ │ │ ├── Cast { cast_to: Int64, expr: #5 } + │ │ │ │ │ │ │ └── 4(i64) │ │ │ │ │ │ └── Like { expr: #4, pattern: "%TIN", negated: false, case_insensitive: false } │ │ │ │ │ └── PhysicalScan { table: part } - │ │ │ │ └── PhysicalScan { table: partsupp } - │ │ │ └── PhysicalScan { table: supplier } - │ │ └── PhysicalProjection { exprs: [ #0, #1, #2 ] } - │ │ └── PhysicalScan { table: nation } - │ └── PhysicalProjection { exprs: [ #0 ] } - │ └── PhysicalFilter - │ ├── cond:Eq - │ │ ├── #1 - │ │ └── "AFRICA" - │ └── PhysicalScan { table: region } - └── PhysicalProjection { exprs: [ #1, #0 ] } - └── PhysicalAgg - ├── aggrs:Agg(Min) - │ └── [ #1 ] - ├── groups: [ #0 ] - └── PhysicalProjection { exprs: [ #0, #1 ] } - └── PhysicalHashJoin { join_type: Inner, left_keys: [ #2 ], right_keys: [ #0 ] } - ├── PhysicalProjection { exprs: [ #0, #1, #4 ] } - │ └── PhysicalHashJoin { join_type: Inner, left_keys: [ #2 ], right_keys: [ #0 ] } - │ ├── PhysicalProjection { exprs: [ #0, #2, #4 ] } - │ │ └── PhysicalHashJoin { join_type: Inner, left_keys: [ #1 ], right_keys: [ #0 ] } - │ │ ├── PhysicalProjection { exprs: [ #0, #1, #3 ] } - │ │ │ └── PhysicalScan { table: partsupp } - │ │ └── PhysicalProjection { exprs: [ #0, #3 ] } - │ │ └── PhysicalScan { table: supplier } - │ └── PhysicalProjection { exprs: [ #0, #2 ] } - │ └── PhysicalScan { table: nation } - └── PhysicalProjection { exprs: [ #0 ] } - └── PhysicalFilter - ├── cond:Eq - │ ├── #1 - │ └── "AFRICA" - └── PhysicalScan { table: region } + │ │ │ │ └── PhysicalScan { table: supplier } + │ │ │ └── PhysicalScan { table: partsupp } + │ │ └── PhysicalScan { table: nation } + │ └── PhysicalFilter + │ ├── cond:Eq + │ │ ├── #1 + │ │ └── "AFRICA" + │ └── PhysicalScan { table: region } + └── PhysicalAgg + ├── aggrs:Agg(Min) + │ └── [ #4 ] + ├── groups: [ #1 ] + └── PhysicalFilter + ├── cond:And + │ ├── Eq + │ │ ├── #0 + │ │ └── #1 + │ ├── Eq + │ │ ├── #6 + │ │ └── #2 + │ ├── Eq + │ │ ├── #9 + │ │ └── #13 + │ ├── Eq + │ │ ├── #15 + │ │ └── #17 + │ └── Eq + │ ├── #18 + │ └── "AFRICA" + └── PhysicalNestedLoopJoin { join_type: Inner, cond: true } + ├── PhysicalAgg { aggrs: [], groups: [ #0 ] } + │ └── PhysicalNestedLoopJoin { join_type: Cross, cond: true } + │ ├── PhysicalNestedLoopJoin { join_type: Cross, cond: true } + │ │ ├── PhysicalNestedLoopJoin { join_type: Cross, cond: true } + │ │ │ ├── PhysicalNestedLoopJoin { join_type: Cross, cond: true } + │ │ │ │ ├── PhysicalScan { table: part } + │ │ │ │ └── PhysicalScan { table: supplier } + │ │ │ └── PhysicalScan { table: partsupp } + │ │ └── PhysicalScan { table: nation } + │ └── PhysicalScan { table: region } + └── PhysicalNestedLoopJoin { join_type: Cross, cond: true } + ├── PhysicalNestedLoopJoin { join_type: Cross, cond: true } + │ ├── PhysicalNestedLoopJoin { join_type: Cross, cond: true } + │ │ ├── PhysicalScan { table: partsupp } + │ │ └── PhysicalScan { table: supplier } + │ └── PhysicalScan { table: nation } + └── PhysicalScan { table: region } */ -- TPC-H Q3 @@ -446,43 +432,33 @@ LogicalLimit { skip: 0(u64), fetch: 10(u64) } └── LogicalAgg ├── exprs:Agg(Sum) │ └── Mul - │ ├── #3 + │ ├── #22 │ └── Sub - │ ├── 1(float) - │ └── #4 - ├── groups: [ #2, #0, #1 ] - └── LogicalProjection { exprs: [ #1, #2, #3, #4, #5 ] } - └── LogicalJoin - ├── join_type: Inner - ├── cond:Eq - │ ├── #0 - │ └── #3 - ├── LogicalProjection { exprs: [ #1, #3, #4 ] } - │ └── LogicalJoin - │ ├── join_type: Inner - │ ├── cond:Eq - │ │ ├── #0 - │ │ └── #2 - │ ├── LogicalProjection { exprs: [ #0 ] } - │ │ └── LogicalFilter - │ │ ├── cond:Eq - │ │ │ ├── #1 - │ │ │ └── "FURNITURE" - │ │ └── LogicalProjection { exprs: [ #0, #6 ] } - │ │ └── LogicalScan { table: customer } - │ └── LogicalFilter - │ ├── cond:Lt - │ │ ├── #2 - │ │ └── 9218(i64) - │ └── LogicalProjection { exprs: [ #0, #1, #4, #7 ] } - │ └── LogicalScan { table: orders } - └── LogicalProjection { exprs: [ #0, #1, #2 ] } - └── LogicalFilter - ├── cond:Gt - │ ├── #3 - │ └── 9218(i64) - └── LogicalProjection { exprs: [ #0, #5, #6, #10 ] } - └── LogicalScan { table: lineitem } + │ ├── Cast { cast_to: Decimal128(20, 0), expr: 1(i64) } + │ └── #23 + ├── groups: [ #17, #12, #15 ] + └── LogicalFilter + ├── cond:And + │ ├── Eq + │ │ ├── #6 + │ │ └── "FURNITURE" + │ ├── Eq + │ │ ├── #0 + │ │ └── #9 + │ ├── Eq + │ │ ├── #17 + │ │ └── #8 + │ ├── Lt + │ │ ├── #12 + │ │ └── Cast { cast_to: Date32, expr: "1995-03-29" } + │ └── Gt + │ ├── #27 + │ └── Cast { cast_to: Date32, expr: "1995-03-29" } + └── LogicalJoin { join_type: Cross, cond: true } + ├── LogicalJoin { join_type: Cross, cond: true } + │ ├── LogicalScan { table: customer } + │ └── LogicalScan { table: orders } + └── LogicalScan { table: lineitem } PhysicalLimit { skip: 0(u64), fetch: 10(u64) } └── PhysicalSort ├── exprs: @@ -494,29 +470,28 @@ PhysicalLimit { skip: 0(u64), fetch: 10(u64) } └── PhysicalAgg ├── aggrs:Agg(Sum) │ └── Mul - │ ├── #3 + │ ├── #22 │ └── Sub - │ ├── 1(float) - │ └── #4 - ├── groups: [ #2, #0, #1 ] - └── PhysicalProjection { exprs: [ #28, #31, #8, #13, #14 ] } - └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #17 ] } + │ ├── Cast { cast_to: Decimal128(20, 0), expr: 1(i64) } + │ └── #23 + ├── groups: [ #17, #12, #15 ] + └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #1 ] } + ├── PhysicalFilter + │ ├── cond:Eq + │ │ ├── #6 + │ │ └── "FURNITURE" + │ └── PhysicalScan { table: customer } + └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ] } ├── PhysicalFilter - │ ├── cond:Eq - │ │ ├── #6 - │ │ └── "FURNITURE" - │ └── PhysicalScan { table: customer } - └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ] } - ├── PhysicalFilter - │ ├── cond:Gt - │ │ ├── #10 - │ │ └── 9218(i64) - │ └── PhysicalScan { table: lineitem } - └── PhysicalFilter - ├── cond:Lt - │ ├── #4 - │ └── 9218(i64) - └── PhysicalScan { table: orders } + │ ├── cond:Lt + │ │ ├── #4 + │ │ └── Cast { cast_to: Date32, expr: "1995-03-29" } + │ └── PhysicalScan { table: orders } + └── PhysicalFilter + ├── cond:Gt + │ ├── #10 + │ └── Cast { cast_to: Date32, expr: "1995-03-29" } + └── PhysicalScan { table: lineitem } */ -- TPC-H Q5 diff --git a/optd-sqlplannertest/tests/tpch/tpch-01-05.yml b/optd-sqlplannertest/tests/tpch/tpch-01-05.yml index 9b4099c9..7990ae74 100644 --- a/optd-sqlplannertest/tests/tpch/tpch-01-05.yml +++ b/optd-sqlplannertest/tests/tpch/tpch-01-05.yml @@ -156,7 +156,7 @@ limit 100; desc: TPC-H Q2 tasks: - - explain[use_df_logical]:logical_optd,physical_optd + - explain:logical_optd,physical_optd - sql: | SELECT l_orderkey, @@ -182,7 +182,7 @@ o_orderdate LIMIT 10; desc: TPC-H Q3 tasks: - - explain[use_df_logical]:logical_optd,physical_optd + - explain:logical_optd,physical_optd - sql: | SELECT n_name AS nation,