[feat](nereids) add more rules to eliminate empty relation (#34997) -branch-2.1 (#35534)

eliminate empty relations for following patterns:
topn->empty
sort->empty
distribute->empty
project->empty

(cherry picked from commit 8340f23946c0c8e40510ce937acd3342cb2e28b7)

## Proposed changes

Issue Number: close #xxx

<!--Describe your changes.-->

## Further comments

If this is a relatively large or complex change, kick off the discussion
at [dev@doris.apache.org](mailto:dev@doris.apache.org) by explaining why
you chose the solution you did and what alternatives you considered,
etc...
This commit is contained in:
minghong
2024-05-28 18:12:42 +08:00
committed by GitHub
parent 84e9a14063
commit 50e81d9db7
16 changed files with 247 additions and 53 deletions

View File

@ -117,7 +117,11 @@ public enum RuleType {
ELIMINATE_JOIN_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_FILTER_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_AGG_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_PROJECT_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_UNION_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_TOPN_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_SORT_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_INTERSECTION_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
ELIMINATE_EXCEPT_ON_EMPTYRELATION(RuleTypeClass.REWRITE),
INFER_PREDICATES(RuleTypeClass.REWRITE),

View File

@ -19,6 +19,7 @@ package org.apache.doris.nereids.rules.rewrite;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.UnaryNode;
import org.apache.doris.nereids.trees.expressions.Alias;
import org.apache.doris.nereids.trees.expressions.ExprId;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
@ -51,11 +52,12 @@ public class EliminateEmptyRelation implements RewriteRuleFactory {
return ImmutableList.of(
// join->empty
logicalJoin(any(), any())
.when(this::hasEmptyRelationChild)
.when(this::canReplaceJoinByEmptyRelation)
.when(join -> hasEmptyRelationChild(join) && canReplaceJoinByEmptyRelation(join)
|| bothChildrenEmpty(join))
.then(join -> new LogicalEmptyRelation(
ConnectContext.get().getStatementContext().getNextRelationId(),
join.getOutput()))
ConnectContext.get().getStatementContext().getNextRelationId(),
join.getOutput())
)
.toRule(RuleType.ELIMINATE_JOIN_ON_EMPTYRELATION),
logicalFilter(logicalEmptyRelation())
.then(filter -> new LogicalEmptyRelation(
@ -68,7 +70,13 @@ public class EliminateEmptyRelation implements RewriteRuleFactory {
ConnectContext.get().getStatementContext().getNextRelationId(),
agg.getOutput())
).toRule(RuleType.ELIMINATE_AGG_ON_EMPTYRELATION),
// proj->empty
logicalProject(logicalEmptyRelation())
.thenApply(ctx -> {
LogicalProject<? extends Plan> project = ctx.root;
return new LogicalEmptyRelation(ConnectContext.get().getStatementContext().getNextRelationId(),
project.getOutputs());
}).toRule(RuleType.ELIMINATE_AGG_ON_EMPTYRELATION),
// after BuildAggForUnion rule, union may have more than 2 children.
logicalUnion(multi()).then(union -> {
if (union.children().isEmpty()) {
@ -116,6 +124,18 @@ public class EliminateEmptyRelation implements RewriteRuleFactory {
return null;
}
}).toRule(RuleType.ELIMINATE_UNION_ON_EMPTYRELATION),
// topn->empty
logicalTopN(logicalEmptyRelation())
.then(topn -> new LogicalEmptyRelation(
ConnectContext.get().getStatementContext().getNextRelationId(),
topn.getOutput()))
.toRule(RuleType.ELIMINATE_TOPN_ON_EMPTYRELATION),
// sort->empty
logicalSort(logicalEmptyRelation())
.then(sort -> new LogicalEmptyRelation(
ConnectContext.get().getStatementContext().getNextRelationId(),
sort.getOutput()))
.toRule(RuleType.ELIMINATE_SORT_ON_EMPTYRELATION),
// set intersect
logicalIntersect(multi()).then(intersect -> {
List<Plan> emptyChildren = intersect.children().stream()
@ -131,6 +151,10 @@ public class EliminateEmptyRelation implements RewriteRuleFactory {
intersect.getOutput());
}
}).toRule(RuleType.ELIMINATE_INTERSECTION_ON_EMPTYRELATION),
// limit -> empty
logicalLimit(logicalEmptyRelation())
.then(UnaryNode::child)
.toRule(RuleType.ELIMINATE_LIMIT_ON_EMPTY_RELATION),
// set except
logicalExcept(multi()).then(except -> {
Plan first = except.child(0);
@ -186,6 +210,10 @@ public class EliminateEmptyRelation implements RewriteRuleFactory {
return join.left() instanceof EmptyRelation || join.right() instanceof EmptyRelation;
}
private boolean bothChildrenEmpty(LogicalJoin<?, ?> join) {
return join.left() instanceof EmptyRelation && join.right() instanceof EmptyRelation;
}
private boolean canReplaceJoinByEmptyRelation(LogicalJoin<?, ?> join) {
return !join.isMarkJoin() && ((join.getJoinType() == JoinType.INNER_JOIN
|| join.getJoinType() == JoinType.LEFT_SEMI_JOIN

View File

@ -19,7 +19,6 @@ package org.apache.doris.nereids.rules.rewrite;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.UnaryNode;
import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator;
import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation;
@ -44,10 +43,7 @@ public class EliminateLimit implements RewriteRuleFactory {
.then(limit -> limit.getLimit() > 0 && limit.getOffset() == 0
? limit.child() : new LogicalEmptyRelation(StatementScopeIdGenerator.newRelationId(),
limit.child().getOutput()))
.toRule(RuleType.ELIMINATE_LIMIT_ON_ONE_ROW_RELATION),
logicalLimit(logicalEmptyRelation())
.then(UnaryNode::child)
.toRule(RuleType.ELIMINATE_LIMIT_ON_EMPTY_RELATION)
.toRule(RuleType.ELIMINATE_LIMIT_ON_ONE_ROW_RELATION)
);
}
}