diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java index 855c28a7a5..3a111a7f4d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Analyzer.java @@ -30,6 +30,7 @@ import org.apache.doris.nereids.rules.analysis.CheckAnalysis; import org.apache.doris.nereids.rules.analysis.CheckPolicy; import org.apache.doris.nereids.rules.analysis.CollectJoinConstraint; import org.apache.doris.nereids.rules.analysis.CollectSubQueryAlias; +import org.apache.doris.nereids.rules.analysis.EliminateDistinctConstant; import org.apache.doris.nereids.rules.analysis.EliminateGroupByConstant; import org.apache.doris.nereids.rules.analysis.EliminateLogicalSelectHint; import org.apache.doris.nereids.rules.analysis.FillUpMissingSlots; @@ -39,6 +40,7 @@ import org.apache.doris.nereids.rules.analysis.NormalizeAggregate; import org.apache.doris.nereids.rules.analysis.NormalizeRepeat; import org.apache.doris.nereids.rules.analysis.OneRowRelationExtractAggregate; import org.apache.doris.nereids.rules.analysis.ProjectToGlobalAggregate; +import org.apache.doris.nereids.rules.analysis.ProjectWithDistinctToAggregate; import org.apache.doris.nereids.rules.analysis.ReplaceExpressionByChildOutput; import org.apache.doris.nereids.rules.analysis.SubqueryToApply; import org.apache.doris.nereids.rules.analysis.VariableToLiteral; @@ -103,6 +105,13 @@ public class Analyzer extends AbstractBatchJobExecutor { bottomUp(new AddInitMaterializationHook()), bottomUp( new ProjectToGlobalAggregate(), + // this rule check's the logicalProject node's isDistinct property + // and replace the logicalProject node with a LogicalAggregate node + // so any rule before this, if create a new logicalProject node + // should make sure isDistinct property is correctly passed around. + // please see rule BindSlotReference or BindFunction for example + new EliminateDistinctConstant(), + new ProjectWithDistinctToAggregate(), new ReplaceExpressionByChildOutput(), new OneRowRelationExtractAggregate() ), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateDistinctConstant.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateDistinctConstant.java new file mode 100644 index 0000000000..0d051ee8c8 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/EliminateDistinctConstant.java @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.rules.analysis; + +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.plans.LimitPhase; +import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; +import org.apache.doris.nereids.trees.plans.logical.LogicalProject; + +/** + * EliminateDistinctConstant. + *
+ * example sql: + *
+ * select distinct 1,2,3 from tbl + * => + * select 1,2,3 from (select 1, 2, 3 from tbl limit 1) as tmp + *+ */ +public class EliminateDistinctConstant extends OneAnalysisRuleFactory { + @Override + public Rule build() { + return RuleType.ELIMINATE_DISTINCT_CONSTANT.build( + logicalProject() + .when(LogicalProject::isDistinct) + .when(project -> project.getProjects().stream().allMatch(Expression::isConstant)) + .then(project -> new LogicalProject(project.getProjects(), new LogicalLimit<>(1, 0, + LimitPhase.ORIGIN, project.child()))) + ); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java index a6916756c1..da642e7661 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java @@ -17,24 +17,13 @@ package org.apache.doris.nereids.rules.analysis; -import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; -import org.apache.doris.nereids.trees.expressions.Alias; -import org.apache.doris.nereids.trees.expressions.NamedExpression; -import org.apache.doris.nereids.trees.expressions.Slot; -import org.apache.doris.nereids.trees.expressions.literal.Literal; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitors; -import org.apache.doris.nereids.trees.plans.LimitPhase; -import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; -import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; -import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import com.google.common.collect.ImmutableList; -import java.util.List; - /** * ProjectToGlobalAggregate. *
@@ -54,110 +43,17 @@ public class ProjectToGlobalAggregate extends OneAnalysisRuleFactory {
@Override
public Rule build() {
return RuleType.PROJECT_TO_GLOBAL_AGGREGATE.build(
- logicalProject().then(project -> {
- project = distinctConstantsToLimit1(project);
- Plan result = projectToAggregate(project);
- return distinctToAggregate(result, project);
- })
+ logicalProject().then(project -> {
+ boolean needGlobalAggregate = project.getProjects()
+ .stream()
+ .anyMatch(p -> p.accept(ExpressionVisitors.CONTAINS_AGGREGATE_CHECKER, null));
+
+ if (needGlobalAggregate) {
+ return new LogicalAggregate<>(ImmutableList.of(), project.getProjects(), project.child());
+ } else {
+ return project;
+ }
+ })
);
}
-
- // select distinct 1,2,3 from tbl
- // ↓
- // select 1,2,3 from (select 1, 2, 3 from tbl limit 1) as tmp
- private static LogicalProject
+ * example sql:
+ *
+ * select distinct value from tbl
+ *
+ * LogicalProject(projects=[distinct value])
+ * |
+ * LogicalOlapScan(table=tbl)
+ * =>
+ * LogicalAggregate(groupBy=[value], output=[value])
+ * |
+ * LogicalOlapScan(table=tbl)
+ *
+ */
+public class ProjectWithDistinctToAggregate extends OneAnalysisRuleFactory {
+ @Override
+ public Rule build() {
+ return RuleType.PROJECT_WITH_DISTINCT_TO_AGGREGATE.build(
+ logicalProject()
+ .when(LogicalProject::isDistinct)
+ .whenNot(project -> project.getProjects().stream().anyMatch(this::hasAggregateFunction))
+ .then(project -> new LogicalAggregate<>(project.getProjects(), false, project.child()))
+ );
+ }
+
+ private boolean hasAggregateFunction(Expression expression) {
+ return expression.anyMatch(AggregateFunction.class::isInstance);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ReplaceExpressionByChildOutput.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ReplaceExpressionByChildOutput.java
index 5dc85811d5..cd53086f96 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ReplaceExpressionByChildOutput.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ReplaceExpressionByChildOutput.java
@@ -53,27 +53,21 @@ public class ReplaceExpressionByChildOutput implements AnalysisRuleFactory {
))
.add(RuleType.REPLACE_SORT_EXPRESSION_BY_CHILD_OUTPUT.build(
logicalSort(logicalAggregate()).then(sort -> {
- LogicalAggregate