From 2c01368b8a6359da6f9dc1cbe74a19d2c9e9d7f4 Mon Sep 17 00:00:00 2001 From: jackwener Date: Thu, 2 Mar 2023 19:15:11 +0800 Subject: [PATCH] [refactor](Nereids): refactor PushdownLimit --- .../nereids/jobs/batch/NereidsRewriter.java | 4 +- .../apache/doris/nereids/rules/RuleType.java | 2 + ...{LimitPushDown.java => PushdownLimit.java} | 77 ++++++++----------- ...shDownTest.java => PushdownLimitTest.java} | 9 ++- 4 files changed, 41 insertions(+), 51 deletions(-) rename fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/{LimitPushDown.java => PushdownLimit.java} (63%) rename fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/{LimitPushDownTest.java => PushdownLimitTest.java} (97%) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriter.java index 28571b1724a038..cfe29964f16f6d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/NereidsRewriter.java @@ -52,7 +52,6 @@ import org.apache.doris.nereids.rules.rewrite.logical.InferJoinNotNull; import org.apache.doris.nereids.rules.rewrite.logical.InferPredicates; import org.apache.doris.nereids.rules.rewrite.logical.InnerToCrossJoin; -import org.apache.doris.nereids.rules.rewrite.logical.LimitPushDown; import org.apache.doris.nereids.rules.rewrite.logical.MergeFilters; import org.apache.doris.nereids.rules.rewrite.logical.MergeProjects; import org.apache.doris.nereids.rules.rewrite.logical.MergeSetOperations; @@ -60,6 +59,7 @@ import org.apache.doris.nereids.rules.rewrite.logical.PruneOlapScanPartition; import org.apache.doris.nereids.rules.rewrite.logical.PruneOlapScanTablet; import org.apache.doris.nereids.rules.rewrite.logical.PushFilterInsideJoin; +import org.apache.doris.nereids.rules.rewrite.logical.PushdownLimit; import org.apache.doris.nereids.rules.rewrite.logical.ReorderJoin; import java.util.List; @@ -191,7 +191,7 @@ public class NereidsRewriter extends BatchRewriteJob { new PruneOlapScanTablet(), new EliminateAggregate(), new MergeSetOperations(), - new LimitPushDown(), + new PushdownLimit(), new BuildAggForUnion() )), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index e87cd11b943e0b..cf55dedddd5da3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -192,6 +192,8 @@ public enum RuleType { PUSH_LIMIT_THROUGH_JOIN(RuleTypeClass.REWRITE), PUSH_LIMIT_THROUGH_PROJECT_JOIN(RuleTypeClass.REWRITE), PUSH_LIMIT_THROUGH_UNION(RuleTypeClass.REWRITE), + PUSH_LIMIT_THROUGH_ONE_ROW_RELATION(RuleTypeClass.REWRITE), + PUSH_LIMIT_THROUGH_EMPTY_RELATION(RuleTypeClass.REWRITE), // adjust nullable ADJUST_NULLABLE_ON_AGGREGATE(RuleTypeClass.REWRITE), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/LimitPushDown.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownLimit.java similarity index 63% rename from fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/LimitPushDown.java rename to fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownLimit.java index 1d1f0029c6dab3..1b2b1a442630be 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/LimitPushDown.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownLimit.java @@ -20,10 +20,9 @@ import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory; +import org.apache.doris.nereids.trees.UnaryNode; import org.apache.doris.nereids.trees.plans.Plan; -import org.apache.doris.nereids.trees.plans.algebra.EmptyRelation; import org.apache.doris.nereids.trees.plans.algebra.Limit; -import org.apache.doris.nereids.trees.plans.algebra.OneRowRelation; import org.apache.doris.nereids.trees.plans.algebra.SetOperation.Qualifier; import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; @@ -40,14 +39,20 @@ *

* Limit can't be push down if it has a valid offset info. */ -public class LimitPushDown implements RewriteRuleFactory { +public class PushdownLimit implements RewriteRuleFactory { @Override public List buildRules() { return ImmutableList.of( // limit -> join logicalLimit(logicalJoin(any(), any())).whenNot(Limit::hasValidOffset) - .then(limit -> limit.withChildren(pushLimitThroughJoin(limit, limit.child()))) + .then(limit -> { + Plan newJoin = pushLimitThroughJoin(limit, limit.child()); + if (newJoin == null || limit.child().children().equals(newJoin.children())) { + return null; + } + return limit.withChildren(newJoin); + }) .toRule(RuleType.PUSH_LIMIT_THROUGH_JOIN), // limit -> project -> join @@ -55,9 +60,11 @@ public List buildRules() { .then(limit -> { LogicalProject> project = limit.child(); LogicalJoin join = project.child(); - return limit.withChildren( - project.withChildren( - pushLimitThroughJoin(limit, join))); + Plan newJoin = pushLimitThroughJoin(limit, join); + if (newJoin == null || join.children().equals(newJoin.children())) { + return null; + } + return limit.withChildren(project.withChildren(newJoin)); }).toRule(RuleType.PUSH_LIMIT_THROUGH_PROJECT_JOIN), // limit -> union @@ -67,11 +74,22 @@ public List buildRules() { LogicalUnion union = limit.child(); ImmutableList newUnionChildren = union.children() .stream() - .map(child -> addLimit(limit, child)) + .map(child -> limit.withChildren(child)) .collect(ImmutableList.toImmutableList()); + if (union.children().equals(newUnionChildren)) { + return null; + } return limit.withChildren(union.withChildren(newUnionChildren)); }) - .toRule(RuleType.PUSH_LIMIT_THROUGH_UNION) + .toRule(RuleType.PUSH_LIMIT_THROUGH_UNION), + logicalLimit(logicalOneRowRelation()) + .then(limit -> limit.getLimit() > 0 + ? limit.child() : new LogicalEmptyRelation(limit.child().getOutput())) + .toRule(RuleType.PUSH_LIMIT_THROUGH_ONE_ROW_RELATION), + logicalLimit(logicalEmptyRelation()) + .then(UnaryNode::child) + .toRule(RuleType.PUSH_LIMIT_THROUGH_EMPTY_RELATION), + new MergeLimits().build() ); } @@ -79,53 +97,22 @@ private Plan pushLimitThroughJoin(LogicalLimit limit, LogicalJoi switch (join.getJoinType()) { case LEFT_OUTER_JOIN: return join.withChildren( - addLimit(limit, join.left()), + limit.withChildren(join.left()), join.right() ); case RIGHT_OUTER_JOIN: return join.withChildren( join.left(), - addLimit(limit, join.right()) + limit.withChildren(join.right()) ); case CROSS_JOIN: return join.withChildren( - addLimit(limit, join.left()), - addLimit(limit, join.right()) + limit.withChildren(join.left()), + limit.withChildren(join.right()) ); - case INNER_JOIN: - if (join.hasJoinCondition()) { - return join; - } else { - return join.withChildren( - addLimit(limit, join.left()), - addLimit(limit, join.right()) - ); - } default: // don't push limit. - return join; - } - } - - private Plan addLimit(LogicalLimit pushdownLimit, Plan plan) { - if (plan instanceof LogicalLimit) { - // Avoid adding duplicate limits on top of the plan, otherwise would result in dead loop - // when applying the rule multiple times. - LogicalLimit limit = (LogicalLimit) plan; - // plan is pure limit and limit value > push down limit value - if (!limit.hasValidOffset() && limit.getLimit() > pushdownLimit.getLimit()) { - // replace limit. - return pushdownLimit.withChildren(limit.child()); - } else { - // return input plan. - return plan; - } - } else if (plan instanceof OneRowRelation) { - return pushdownLimit.getLimit() > 0 ? plan : new LogicalEmptyRelation(plan.getOutput()); - } else if (plan instanceof EmptyRelation) { - return plan; - } else { - return pushdownLimit.withChildren(plan); + return null; } } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/LimitPushDownTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownLimitTest.java similarity index 97% rename from fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/LimitPushDownTest.java rename to fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownLimitTest.java index 89a2b4f0b5a759..ea1fc5894297df 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/LimitPushDownTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownLimitTest.java @@ -48,7 +48,7 @@ import java.util.function.Function; import java.util.stream.Collectors; -class LimitPushDownTest extends TestWithFeService implements MemoPatternMatchSupported { +class PushdownLimitTest extends TestWithFeService implements MemoPatternMatchSupported { private Plan scanScore = new LogicalOlapScan(RelationUtil.newRelationId(), PlanConstructor.score); private Plan scanStudent = new LogicalOlapScan(RelationUtil.newRelationId(), PlanConstructor.student); @@ -173,7 +173,7 @@ public void testPushLimitThroughInnerJoin() { logicalJoin( logicalLimit(logicalOlapScan().when(s -> s.equals(scanScore))), logicalLimit(logicalOlapScan().when(s -> s.equals(scanStudent))) - ).when(j -> j.getJoinType() == JoinType.INNER_JOIN) + ) ) ) ); @@ -182,7 +182,7 @@ public void testPushLimitThroughInnerJoin() { logicalJoin( logicalLimit(logicalOlapScan().when(s -> s.equals(scanScore))), logicalLimit(logicalOlapScan().when(s -> s.equals(scanStudent))) - ).when(j -> j.getJoinType() == JoinType.INNER_JOIN) + ) ) ); } @@ -241,7 +241,8 @@ private void test(JoinType joinType, boolean hasProject, PatternDescriptor