Skip to content
This repository was archived by the owner on Jan 7, 2025. It is now read-only.

Commit 34bfb62

Browse files
authored
fix(core): logical property in heuristics, depjoin schema in df-repr (#198)
* Re-infer properties each time before rule invoke * Fix schema of depjoin * Fix the position of the eliminate projection rule, in bottom-up, it should be applied before simplify expr close https://github.com/cmu-db/optd/issues/197 --------- Signed-off-by: Alex Chi <[email protected]>
1 parent d340bbb commit 34bfb62

File tree

6 files changed

+70
-66
lines changed

6 files changed

+70
-66
lines changed

optd-core/src/heuristics/optimizer.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{collections::HashMap, sync::Arc};
22

3-
use anyhow::Result;
3+
use anyhow::{Context, Result};
44
use itertools::Itertools;
55
use std::any::Any;
66

@@ -123,15 +123,17 @@ impl<T: RelNodeTyp> HeuristicsOptimizer<T> {
123123
fn optimize_inputs(&mut self, inputs: &[RelNodeRef<T>]) -> Result<Vec<RelNodeRef<T>>> {
124124
let mut optimized_inputs = Vec::with_capacity(inputs.len());
125125
for input in inputs {
126-
optimized_inputs.push(self.optimize(input.clone())?);
126+
optimized_inputs.push(self.optimize_inner(input.clone())?);
127127
}
128128
Ok(optimized_inputs)
129129
}
130130

131131
fn apply_rules(&mut self, mut root_rel: RelNodeRef<T>) -> Result<RelNodeRef<T>> {
132-
for rule in self.rules.as_ref() {
132+
for rule in self.rules.clone().as_ref() {
133+
// Properties only matter for applying rules, therefore applying it before each rule invoke.
133134
let matcher = rule.matcher();
134135
if let Some(picks) = match_and_pick(matcher, root_rel.clone()) {
136+
self.infer_properties(root_rel.clone());
135137
let mut results = rule.apply(self, picks);
136138
assert!(results.len() <= 1);
137139
if !results.is_empty() {
@@ -154,15 +156,9 @@ impl<T: RelNodeTyp> HeuristicsOptimizer<T> {
154156
}
155157
.into(),
156158
)?;
157-
self.infer_properties(root_rel.clone());
158-
self.properties.insert(
159-
node.clone(),
160-
self.properties.get(&root_rel.clone()).unwrap().clone(),
161-
);
162159
Ok(node)
163160
}
164161
ApplyOrder::TopDown => {
165-
self.infer_properties(root_rel.clone());
166162
let root_rel = self.apply_rules(root_rel)?;
167163
let optimized_children = self.optimize_inputs(&root_rel.children)?;
168164
let node: Arc<RelNode<T>> = RelNode {
@@ -171,11 +167,6 @@ impl<T: RelNodeTyp> HeuristicsOptimizer<T> {
171167
data: root_rel.data.clone(),
172168
}
173169
.into();
174-
self.infer_properties(root_rel.clone());
175-
self.properties.insert(
176-
node.clone(),
177-
self.properties.get(&root_rel.clone()).unwrap().clone(),
178-
);
179170
Ok(node)
180171
}
181172
}
@@ -221,8 +212,20 @@ impl<T: RelNodeTyp> Optimizer<T> for HeuristicsOptimizer<T> {
221212
root_rel: RelNodeRef<T>,
222213
idx: usize,
223214
) -> P::Prop {
224-
let props = self.properties.get(&root_rel).unwrap();
215+
let props = self
216+
.properties
217+
.get(&root_rel)
218+
.with_context(|| format!("cannot obtain properties for {}", root_rel))
219+
.unwrap();
225220
let prop = props[idx].as_ref();
226-
prop.downcast_ref::<P::Prop>().unwrap().clone()
221+
prop.downcast_ref::<P::Prop>()
222+
.with_context(|| {
223+
format!(
224+
"cannot downcast property at idx {} into provided property instance",
225+
idx
226+
)
227+
})
228+
.unwrap()
229+
.clone()
227230
}
228231
}

optd-datafusion-repr/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl DatafusionOptimizer {
8585
pub fn default_heuristic_rules(
8686
) -> Vec<Arc<dyn Rule<OptRelNodeTyp, HeuristicsOptimizer<OptRelNodeTyp>>>> {
8787
vec![
88+
Arc::new(EliminateProjectRule::new()),
8889
Arc::new(SimplifyFilterRule::new()),
8990
Arc::new(SimplifyJoinCondRule::new()),
9091
Arc::new(EliminateFilterRule::new()),
@@ -99,8 +100,6 @@ impl DatafusionOptimizer {
99100
Arc::new(DepJoinPastAgg::new()),
100101
Arc::new(ProjectMergeRule::new()),
101102
Arc::new(FilterMergeRule::new()),
102-
// disabled due to logical properties are not implemented in heuristics
103-
// Arc::new(EliminateProjectRule::new()),
104103
]
105104
}
106105

optd-datafusion-repr/src/properties/schema.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ impl PropertyBuilder<OptRelNodeTyp> for SchemaPropertyBuilder {
7373
}
7474
OptRelNodeTyp::Projection => children[1].clone(),
7575
OptRelNodeTyp::Filter => children[0].clone(),
76-
OptRelNodeTyp::DepJoin(_) | OptRelNodeTyp::Join(_) => {
76+
OptRelNodeTyp::DepJoin(_) => children[0].clone(),
77+
OptRelNodeTyp::Join(_) => {
7778
let mut schema = children[0].clone();
7879
let schema2 = children[1].clone();
7980
schema.fields.extend(schema2.fields);

optd-sqlplannertest/tests/basic/empty_relation.planner.sql

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ LogicalProjection { exprs: [ #0, #1, #2, #3 ] }
3939
└── LogicalJoin { join_type: Inner, cond: false }
4040
├── LogicalScan { table: t1 }
4141
└── LogicalScan { table: t2 }
42+
LogicalEmptyRelation { produce_one_row: false }
4243
PhysicalEmptyRelation { produce_one_row: false }
4344
*/
4445

optd-sqlplannertest/tests/basic/empty_relation.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@
1717
select 64+1 from t1 inner join t2 on false;
1818
desc: Test whether the optimizer eliminates join to empty relation
1919
tasks:
20-
- explain:logical_optd,physical_optd
21-
- execute
20+
- explain:logical_optd,optimized_logical_optd,physical_optd
21+
- execute

optd-sqlplannertest/tests/tpch/tpch-11-15.planner.sql

+45-45
Original file line numberDiff line numberDiff line change
@@ -567,50 +567,50 @@ LogicalSort
567567
PhysicalSort
568568
├── exprs:SortOrder { order: Asc }
569569
│ └── #0
570-
└── PhysicalProjection { exprs: [ #3, #4, #5, #7, #2 ] }
571-
└── PhysicalHashJoin { join_type: Inner, left_keys: [ #1 ], right_keys: [ #0 ] }
572-
├── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #1 ] }
573-
│ ├── PhysicalAgg
574-
│ │ ── aggrs:Agg(Max)
575-
│ │ └── [ #0 ]
576-
│ ├── groups: []
577-
└── PhysicalProjection { exprs: [ #1 ] }
578-
── PhysicalAgg
579-
── aggrs:Agg(Sum)
580-
── Mul
581-
── #1
582-
── Sub
583-
── 1(float)
584-
│ └── #2
585-
── groups: [ #0 ]
586-
└── PhysicalProjection { exprs: [ #2, #5, #6 ] }
587-
── PhysicalFilter
588-
├── cond:And
589-
│ ├── Geq
590-
│ │ ── #10
591-
└── 8401(i64)
592-
── Lt
593-
── #10
594-
│ └── 8491(i64)
595-
│ │ └── PhysicalScan { table: lineitem }
596-
── PhysicalAgg
597-
── aggrs:Agg(Sum)
598-
│ └── Mul
599-
── #1
600-
── Sub
601-
── 1(float)
602-
── #2
603-
├── groups: [ #0 ]
604-
── PhysicalProjection { exprs: [ #2, #5, #6 ] }
605-
└── PhysicalFilter
606-
── cond:And
607-
├── Geq
608-
│ ├── #10
609-
│ │ ── 8401(i64)
610-
│ └── Lt
611-
── #10
612-
── 8491(i64)
613-
└── PhysicalScan { table: lineitem }
614-
└── PhysicalScan { table: supplier }
570+
└── PhysicalProjection { exprs: [ #1, #2, #3, #5, #9 ] }
571+
└── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #8 ] }
572+
├── PhysicalAgg
573+
│ ├── aggrs:Agg(Max)
574+
│ │ ── [ #0 ]
575+
── groups: []
576+
── PhysicalProjection { exprs: [ #1 ] }
577+
└── PhysicalAgg
578+
── aggrs:Agg(Sum)
579+
── Mul
580+
── #1
581+
│ │ ── Sub
582+
── 1(float)
583+
│ │ ── #2
584+
── groups: [ #0 ]
585+
── PhysicalProjection { exprs: [ #2, #5, #6 ] }
586+
└── PhysicalFilter
587+
── cond:And
588+
├── Geq
589+
│ ├── #10
590+
│ │ │ ── 8401(i64)
591+
│ │ └── Lt
592+
── #10
593+
│ │ ── 8491(i64)
594+
└── PhysicalScan { table: lineitem }
595+
└── PhysicalHashJoin { join_type: Inner, left_keys: [ #0 ], right_keys: [ #0 ] }
596+
── PhysicalScan { table: supplier }
597+
── PhysicalAgg
598+
── aggrs:Agg(Sum)
599+
── Mul
600+
── #1
601+
── Sub
602+
── 1(float)
603+
└── #2
604+
── groups: [ #0 ]
605+
└── PhysicalProjection { exprs: [ #2, #5, #6 ] }
606+
── PhysicalFilter
607+
├── cond:And
608+
│ ├── Geq
609+
│ │ ── #10
610+
└── 8401(i64)
611+
── Lt
612+
── #10
613+
│ └── 8491(i64)
614+
└── PhysicalScan { table: lineitem }
615615
*/
616616

0 commit comments

Comments
 (0)