diff --git a/optd-core/src/cascades/memo.rs b/optd-core/src/cascades/memo.rs index 85120832..fcf63bef 100644 --- a/optd-core/src/cascades/memo.rs +++ b/optd-core/src/cascades/memo.rs @@ -407,7 +407,8 @@ impl NaiveMemo { trace!(event = "merge_group", merge_into = %merge_into, merge_from = %merge_from); let group_merge_from = self.groups.remove(&merge_from).unwrap(); let group_merge_into = self.groups.get_mut(&merge_into).unwrap(); - // TODO: update winner, cost and properties + + // Merge expressions for from_expr in group_merge_from.group_exprs { let ret = self.expr_id_to_group_id.insert(from_expr, merge_into); assert!(ret.is_some()); @@ -415,6 +416,20 @@ impl NaiveMemo { } self.merged_group_mapping.insert(merge_from, merge_into); + // Merge winner + if let Some(winner) = group_merge_from.info.winner.as_full_winner() { + match &group_merge_into.info.winner { + Winner::Impossible | Winner::Unknown => { + group_merge_into.info.winner = Winner::Full(winner.clone()); + } + Winner::Full(winner_into) => { + if winner.total_weighted_cost < winner_into.total_weighted_cost { + group_merge_into.info.winner = Winner::Full(winner.clone()); + } + } + } + } + // Update all indexes and other data structures // 1. update merged group mapping -- could be optimized with union find for (_, mapped_to) in self.merged_group_mapping.iter_mut() { diff --git a/optd-sqlplannertest/tests/joins/join_enumerate.planner.sql b/optd-sqlplannertest/tests/joins/join_enumerate.planner.sql index 5cdad09a..f7d5038b 100644 --- a/optd-sqlplannertest/tests/joins/join_enumerate.planner.sql +++ b/optd-sqlplannertest/tests/joins/join_enumerate.planner.sql @@ -132,11 +132,12 @@ PhysicalHashJoin { join_type: Inner, left_keys: [ #1 ], right_keys: [ #0 ] } (Join (Join t3 t1) t2) (Join (Join t3 t2) t1) -PhysicalHashJoin { join_type: Inner, left_keys: [ #1 ], right_keys: [ #0 ] } -├── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ] } -│ ├── PhysicalScan { table: t1 } -│ └── PhysicalScan { table: t2 } -└── PhysicalScan { table: t3 } +PhysicalProjection { exprs: [ #4, #5, #0, #1, #2, #3 ] } +└── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #2 ] } + ├── PhysicalScan { table: t2 } + └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #1 ] } + ├── PhysicalScan { table: t3 } + └── PhysicalScan { table: t1 } 0 0 0 200 0 300 1 1 1 201 1 301 2 2 2 202 2 302 diff --git a/optd-sqlplannertest/tests/tpch/q17.planner.sql b/optd-sqlplannertest/tests/tpch/q17.planner.sql index 0f9b7e96..1410e2e0 100644 --- a/optd-sqlplannertest/tests/tpch/q17.planner.sql +++ b/optd-sqlplannertest/tests/tpch/q17.planner.sql @@ -75,57 +75,55 @@ PhysicalProjection │ └── [ #5 ] ├── groups: [] └── PhysicalProjection { exprs: [ #0, #1, #2, #3, #4, #5, #6, #7, #8, #9, #10, #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #24, #26 ] } - └── PhysicalProjection { exprs: [ #11, #12, #13, #14, #15, #16, #17, #18, #19, #20, #21, #22, #23, #24, #25, #26, #2, #3, #4, #5, #6, #7, #8, #9, #10, #0, #1 ] } - └── PhysicalNestedLoopJoin - ├── join_type: Inner - ├── cond:And - │ ├── Eq - │ │ ├── #2 - │ │ └── #12 - │ └── Lt - │ ├── Cast { cast_to: Decimal128(30, 15), child: #15 } - │ └── #1 - ├── PhysicalProjection { exprs: [ #9, #10, #0, #1, #2, #3, #4, #5, #6, #7, #8 ] } - │ └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ] } - │ ├── PhysicalFilter - │ │ ├── cond:And - │ │ │ ├── Eq - │ │ │ │ ├── #3 - │ │ │ │ └── "Brand#13" - │ │ │ └── Eq - │ │ │ ├── #6 - │ │ │ └── "JUMBO PKG" - │ │ └── PhysicalScan { table: part } - │ └── PhysicalProjection - │ ├── exprs: - │ │ ┌── #0 - │ │ └── Cast - │ │ ├── cast_to: Decimal128(30, 15) - │ │ ├── child:Mul - │ │ │ ├── 0.2(float) - │ │ │ └── Cast { cast_to: Float64, child: #1 } + └── PhysicalNestedLoopJoin + ├── join_type: Inner + ├── cond:And + │ ├── Eq + │ │ ├── #16 + │ │ └── #1 + │ └── Lt + │ ├── Cast { cast_to: Decimal128(30, 15), child: #4 } + │ └── #26 + ├── PhysicalScan { table: lineitem } + └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ] } + ├── PhysicalFilter + │ ├── cond:And + │ │ ├── Eq + │ │ │ ├── #3 + │ │ │ └── "Brand#13" + │ │ └── Eq + │ │ ├── #6 + │ │ └── "JUMBO PKG" + │ └── PhysicalScan { table: part } + └── PhysicalProjection + ├── exprs: + │ ┌── #0 + │ └── Cast + │ ├── cast_to: Decimal128(30, 15) + │ ├── child:Mul + │ │ ├── 0.2(float) + │ │ └── Cast { cast_to: Float64, child: #1 } - │ └── PhysicalProjection { exprs: [ #0, #2 ] } - │ └── PhysicalNestedLoopJoin - │ ├── join_type: LeftOuter - │ ├── cond:And - │ │ └── Eq - │ │ ├── #0 - │ │ └── #1 - │ ├── PhysicalAgg { aggrs: [], groups: [ #16 ] } - │ │ └── PhysicalNestedLoopJoin { join_type: Inner, cond: true } - │ │ ├── PhysicalScan { table: lineitem } - │ │ └── PhysicalScan { table: part } - │ └── PhysicalAgg - │ ├── aggrs:Agg(Avg) - │ │ └── [ #5 ] - │ ├── groups: [ #0 ] - │ └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #1 ] } - │ ├── PhysicalAgg { aggrs: [], groups: [ #16 ] } - │ │ └── PhysicalNestedLoopJoin { join_type: Inner, cond: true } - │ │ ├── PhysicalScan { table: lineitem } - │ │ └── PhysicalScan { table: part } - │ └── PhysicalScan { table: lineitem } - └── PhysicalScan { table: lineitem } + └── PhysicalProjection { exprs: [ #0, #2 ] } + └── PhysicalNestedLoopJoin + ├── join_type: LeftOuter + ├── cond:And + │ └── Eq + │ ├── #0 + │ └── #1 + ├── PhysicalAgg { aggrs: [], groups: [ #16 ] } + │ └── PhysicalNestedLoopJoin { join_type: Inner, cond: true } + │ ├── PhysicalScan { table: lineitem } + │ └── PhysicalScan { table: part } + └── PhysicalAgg + ├── aggrs:Agg(Avg) + │ └── [ #5 ] + ├── groups: [ #0 ] + └── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #1 ] } + ├── PhysicalAgg { aggrs: [], groups: [ #16 ] } + │ └── PhysicalNestedLoopJoin { join_type: Inner, cond: true } + │ ├── PhysicalScan { table: lineitem } + │ └── PhysicalScan { table: part } + └── PhysicalScan { table: lineitem } */