This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch branch-2.1 in repository https://gitbox.apache.org/repos/asf/doris.git
commit f64a9a33f8e28d8f13af476cb8b508fd35067203 Author: 谢健 <jianx...@gmail.com> AuthorDate: Fri Mar 15 19:21:26 2024 +0800 [fix](Nereids): don't pushdown project when project contains both side of join (#32214) --- .../join/PushDownProjectThroughSemiJoin.java | 19 +++++++++++++ .../join/PushDownProjectThroughSemiJoinTest.java | 32 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoin.java index 0629092f451..66735d39b98 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoin.java @@ -38,6 +38,7 @@ import java.util.stream.Collectors; /** * 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 * | | @@ -61,6 +62,9 @@ public class PushDownProjectThroughSemiJoin implements ExplorationRuleFactory { .whenNot(j -> j.left().child().hasDistributeHint()) .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.PUSH_DOWN_PROJECT_THROUGH_SEMI_JOIN_LEFT), @@ -72,12 +76,27 @@ public class PushDownProjectThroughSemiJoin implements ExplorationRuleFactory { .whenNot(j -> j.right().child().hasDistributeHint()) .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.PUSH_DOWN_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); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoinTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoinTest.java index 8c5a29f0d55..bccd3056d35 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoinTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/join/PushDownProjectThroughSemiJoinTest.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.trees.expressions.Add; 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; @@ -133,4 +134,35 @@ class PushDownProjectThroughSemiJoinTest implements MemoPatternMatchSupported { ) ); } + + @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())); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org