Skip to content

Commit 380d288

Browse files
authored
feat(optimizer): part support decorrelating correlated subqueries in join conditions (#17871)
* refactor: improve subquery handling in decorrelate and join operators Signed-off-by: coldWater <[email protected]> * refactor: enhance subquery handling in EvalScalar, Filter, ProjectSet, Aggregate, Window, Sort, and Join operators Signed-off-by: coldWater <[email protected]> * test Signed-off-by: coldWater <[email protected]> --------- Signed-off-by: coldWater <[email protected]>
1 parent 10b2695 commit 380d288

File tree

5 files changed

+297
-243
lines changed

5 files changed

+297
-243
lines changed

โ€Žsrc/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/decorrelate.rs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl SubqueryDecorrelatorOptimizer {
5757
// 1. If the subquery is correlated, we will try to decorrelate it into `SemiJoin`
5858
pub fn try_decorrelate_simple_subquery(
5959
&self,
60-
input: &SExpr,
60+
outer: &SExpr,
6161
subquery: &SubqueryExpr,
6262
) -> Result<Option<SExpr>> {
6363
if subquery.outer_columns.is_empty() {
@@ -80,7 +80,7 @@ impl SubqueryDecorrelatorOptimizer {
8080
// EvalScalar
8181
// \
8282
// Get
83-
let matchers = vec![
83+
let matchers = [
8484
Matcher::MatchOp {
8585
op_type: RelOp::EvalScalar,
8686
children: vec![Matcher::MatchOp {
@@ -105,32 +105,23 @@ impl SubqueryDecorrelatorOptimizer {
105105
}],
106106
},
107107
];
108-
let mut matched = false;
109-
for matcher in matchers {
110-
if matcher.matches(&subquery.subquery) {
111-
matched = true;
112-
break;
113-
}
114-
}
115-
if !matched {
108+
if !matchers
109+
.iter()
110+
.any(|matcher| matcher.matches(&subquery.subquery))
111+
{
116112
return Ok(None);
117113
}
118114

119115
let filter_tree = subquery
120116
.subquery // EvalScalar
121-
.child(0)?; // Filter
117+
.unary_child(); // Filter
118+
let filter: Filter = filter_tree.plan().clone().try_into()?;
122119
let filter_expr = RelExpr::with_s_expr(filter_tree);
123-
let filter: Filter = subquery
124-
.subquery // EvalScalar
125-
.child(0)? // Filter
126-
.plan()
127-
.clone()
128-
.try_into()?;
120+
129121
let filter_prop = filter_expr.derive_relational_prop()?;
130122
let filter_child_prop = filter_expr.derive_relational_prop_child(0)?;
131123

132-
let input_expr = RelExpr::with_s_expr(input);
133-
let input_prop = input_expr.derive_relational_prop()?;
124+
let outer_prop = outer.derive_relational_prop()?;
134125

135126
// First, we will check if all the outer columns are in the filter.
136127
if !filter_child_prop.outer_columns.is_empty() {
@@ -145,7 +136,7 @@ impl SubqueryDecorrelatorOptimizer {
145136
let mut left_filters = vec![];
146137
let mut right_filters = vec![];
147138
for pred in filter.predicates.iter() {
148-
let join_condition = JoinPredicate::new(pred, &input_prop, &filter_prop);
139+
let join_condition = JoinPredicate::new(pred, &outer_prop, &filter_prop);
149140
match join_condition {
150141
JoinPredicate::Left(filter) | JoinPredicate::ALL(filter) => {
151142
left_filters.push(filter.clone());
@@ -197,7 +188,7 @@ impl SubqueryDecorrelatorOptimizer {
197188
};
198189

199190
// Rewrite plan to semi-join.
200-
let mut left_child = input.clone();
191+
let mut left_child = outer.clone();
201192
if !left_filters.is_empty() {
202193
left_child = SExpr::create_unary(
203194
Arc::new(

0 commit comments

Comments
ย (0)