Skip to content

Commit

Permalink
[fix](Nereids): don't pushdown project when project contains both sid…
Browse files Browse the repository at this point in the history
…e of join (#32214)
  • Loading branch information
keanji-x committed Mar 18, 2024
1 parent 30b0e84 commit 9b005ca
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
/**
* Rule for pushdown project through left-semi/anti join
* Just push down project inside join to avoid to push the top of Join-Cluster.
* Note this rule is only used to push down project between join for join ordering.
* <pre>
* Join Join
* | |
Expand All @@ -61,6 +62,9 @@ public List<Rule> buildRules() {
.whenNot(j -> j.left().child().hasJoinHint())
.then(topJoin -> {
LogicalProject<LogicalJoin<GroupPlan, GroupPlan>> project = topJoin.left();
if (projectBothJoinSide(project)) {
return null;
}
Plan newLeft = pushdownProject(project);
return topJoin.withChildren(newLeft, topJoin.right());
}).toRule(RuleType.PUSHDOWN_PROJECT_THROUGH_SEMI_JOIN_LEFT),
Expand All @@ -72,12 +76,27 @@ public List<Rule> buildRules() {
.whenNot(j -> j.right().child().hasJoinHint())
.then(topJoin -> {
LogicalProject<LogicalJoin<GroupPlan, GroupPlan>> project = topJoin.right();
if (projectBothJoinSide(project)) {
return null;
}
Plan newRight = pushdownProject(project);
return topJoin.withChildren(topJoin.left(), newRight);
}).toRule(RuleType.PUSHDOWN_PROJECT_THROUGH_SEMI_JOIN_RIGHT)
);
}

private boolean projectBothJoinSide(LogicalProject<LogicalJoin<GroupPlan, GroupPlan>> project) {
// if project contains both side of join, it can't be pushed.
// such as:
// Project(l, null as r)
// ------ L(l) left anti join R(r)
LogicalJoin<?, ?> join = project.child();
Set<Slot> projectOutput = project.getOutputSet();
boolean containLeft = join.left().getOutput().stream().anyMatch(projectOutput::contains);
boolean containRight = join.right().getOutput().stream().anyMatch(projectOutput::contains);
return containRight && containLeft;
}

private Plan pushdownProject(LogicalProject<LogicalJoin<GroupPlan, GroupPlan>> project) {
LogicalJoin<GroupPlan, GroupPlan> join = project.child();
Set<Slot> conditionLeftSlots = CBOUtils.joinChildConditionSlots(join, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.literal.Literal;
import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
Expand Down Expand Up @@ -133,4 +134,35 @@ void pushComplexProject() {
)
);
}

@Test
void testProjectLiteral() {
List<NamedExpression> projectExprs = ImmutableList.of(
new Alias(new Add(scan1.getOutput().get(0), Literal.of(1)), "alias"),
new Alias(scan2.getOutput().get(0).getExprId(), new NullLiteral(), scan2.getOutput().get(0).getName())
);
// complex projection contain ti.id, which isn't in Join Condition
LogicalPlan plan = new LogicalPlanBuilder(scan1)
.join(scan2, JoinType.LEFT_SEMI_JOIN, Pair.of(1, 1))
.projectExprs(projectExprs)
.join(scan3, JoinType.INNER_JOIN, Pair.of(1, 1))
.build();
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyExploration(PushdownProjectThroughSemiJoin.INSTANCE.buildRules())
.nonMatch(logicalJoin(logicalJoin(logicalProject(), group()), group()));

projectExprs = ImmutableList.of(
new Alias(new Add(scan2.getOutput().get(0), Literal.of(1)), "alias"),
new Alias(scan1.getOutput().get(0).getExprId(), new NullLiteral(), scan2.getOutput().get(0).getName())
);
// complex projection contain ti.id, which isn't in Join Condition
plan = new LogicalPlanBuilder(scan1)
.join(scan2, JoinType.RIGHT_SEMI_JOIN, Pair.of(1, 1))
.projectExprs(projectExprs)
.join(scan3, JoinType.INNER_JOIN, Pair.of(1, 1))
.build();
PlanChecker.from(MemoTestUtils.createConnectContext(), plan)
.applyExploration(PushdownProjectThroughSemiJoin.INSTANCE.buildRules())
.nonMatch(logicalJoin(logicalJoin(logicalProject(), group()), group()));
}
}

0 comments on commit 9b005ca

Please sign in to comment.