You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2024/01/23 05:22:37 UTC
(doris) 06/09: [Enhancement](plan) Optimize preagg for aggregate function (#28886)
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 2499ca6d89ba5c3d950c0bcff3b4d289afb82f7d
Author: Xujian Duan <50...@users.noreply.github.com>
AuthorDate: Tue Jan 23 11:17:53 2024 +0800
[Enhancement](plan) Optimize preagg for aggregate function (#28886)
---
.../main/java/org/apache/doris/analysis/Expr.java | 8 ++
.../org/apache/doris/analysis/LiteralExpr.java | 29 ++++++
.../mv/SelectMaterializedIndexWithAggregate.java | 103 +++++++++++++++++++++
.../nereids/trees/expressions/Expression.java | 4 +
.../nereids/trees/expressions/literal/Literal.java | 23 +++++
.../apache/doris/planner/SingleNodePlanner.java | 47 ++++++++--
.../rules/rewrite/mv/SelectMvIndexTest.java | 89 ++++++++++++++++++
.../rules/rewrite/mv/SelectRollupIndexTest.java | 2 +-
8 files changed, 294 insertions(+), 11 deletions(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java
index adb7621a346..465c2c947c8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java
@@ -2627,5 +2627,13 @@ public abstract class Expr extends TreeNode<Expr> implements ParseNode, Cloneabl
expr.replaceSlot(tuple);
}
}
+
+ public boolean isNullLiteral() {
+ return this instanceof NullLiteral;
+ }
+
+ public boolean isZeroLiteral() {
+ return this instanceof LiteralExpr && ((LiteralExpr) this).isZero();
+ }
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java
index ce89b2fc3c9..0814235f0a3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java
@@ -34,8 +34,10 @@ import org.apache.logging.log4j.Logger;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
public abstract class LiteralExpr extends Expr implements Comparable<LiteralExpr> {
@@ -449,4 +451,31 @@ public abstract class LiteralExpr extends Expr implements Comparable<LiteralExpr
public boolean matchExprs(List<Expr> exprs, SelectStmt stmt, boolean ignoreAlias, TupleDescriptor tuple) {
return true;
}
+
+ /** whether is ZERO value **/
+ public boolean isZero() {
+ boolean isZero = false;
+ switch (type.getPrimitiveType()) {
+ case TINYINT:
+ case SMALLINT:
+ case INT:
+ case BIGINT:
+ case LARGEINT:
+ isZero = this.getLongValue() == 0;
+ break;
+ case FLOAT:
+ case DOUBLE:
+ isZero = this.getDoubleValue() == 0.0f;
+ break;
+ case DECIMALV2:
+ case DECIMAL32:
+ case DECIMAL64:
+ case DECIMAL128:
+ case DECIMAL256:
+ isZero = Objects.equals(((DecimalLiteral) this).getValue(), BigDecimal.ZERO);
+ break;
+ default:
+ }
+ return isZero;
+ }
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java
index a254e8d67d1..50d48ab8051 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java
@@ -32,6 +32,7 @@ import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory;
import org.apache.doris.nereids.rules.rewrite.mv.AbstractSelectMaterializedIndexRule.SlotContext;
import org.apache.doris.nereids.trees.expressions.Alias;
+import org.apache.doris.nereids.trees.expressions.CaseWhen;
import org.apache.doris.nereids.trees.expressions.Cast;
import org.apache.doris.nereids.trees.expressions.ExprId;
import org.apache.doris.nereids.trees.expressions.Expression;
@@ -40,6 +41,7 @@ import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotNotFromChildren;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.expressions.VirtualSlotReference;
+import org.apache.doris.nereids.trees.expressions.WhenClause;
import org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction;
import org.apache.doris.nereids.trees.expressions.functions.agg.BitmapUnion;
import org.apache.doris.nereids.trees.expressions.functions.agg.BitmapUnionCount;
@@ -53,8 +55,10 @@ import org.apache.doris.nereids.trees.expressions.functions.agg.Sum;
import org.apache.doris.nereids.trees.expressions.functions.combinator.MergeCombinator;
import org.apache.doris.nereids.trees.expressions.functions.combinator.StateCombinator;
import org.apache.doris.nereids.trees.expressions.functions.scalar.HllHash;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.If;
import org.apache.doris.nereids.trees.expressions.functions.scalar.ToBitmap;
import org.apache.doris.nereids.trees.expressions.functions.scalar.ToBitmapWithCheck;
+import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
@@ -79,6 +83,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -879,6 +884,9 @@ public class SelectMaterializedIndexWithAggregate extends AbstractSelectMaterial
if (slotOpt.isPresent() && context.keyNameToColumn.containsKey(normalizeName(slotOpt.get().toSql()))) {
return PreAggStatus.on();
}
+ if (count.child(0).arity() != 0) {
+ return checkSubExpressions(count, null, context);
+ }
}
return PreAggStatus.off(String.format(
"Count distinct is only valid for key columns, but meet %s.", count.toSql()));
@@ -963,11 +971,106 @@ public class SelectMaterializedIndexWithAggregate extends AbstractSelectMaterial
return PreAggStatus.off(String.format("Aggregate operator don't match, aggregate function: %s"
+ ", column aggregate type: %s", aggFunc.toSql(), aggType));
}
+ } else if (!aggFunc.child(0).children().isEmpty()) {
+ return checkSubExpressions(aggFunc, matchingAggType, ctx);
} else {
return PreAggStatus.off(String.format("Slot(%s) in %s is neither key column nor value column.",
childNameWithFuncName, aggFunc.toSql()));
}
}
+
+ // check sub expressions in AggregateFunction.
+ private PreAggStatus checkSubExpressions(AggregateFunction aggFunc, AggregateType matchingAggType,
+ CheckContext ctx) {
+ Expression child = aggFunc.child(0);
+ List<Expression> conditionExps = new ArrayList<>();
+ List<Expression> returnExps = new ArrayList<>();
+
+ // ignore cast
+ while (child instanceof Cast) {
+ if (!((Cast) child).getDataType().isNumericType()) {
+ return PreAggStatus.off(String.format("[%s] is not numeric CAST.", child.toSql()));
+ }
+ child = child.child(0);
+ }
+ // step 1: extract all condition exprs and return exprs
+ if (child instanceof If) {
+ conditionExps.add(child.child(0));
+ returnExps.add(child.child(1));
+ returnExps.add(child.child(2));
+ } else if (child instanceof CaseWhen) {
+ CaseWhen caseWhen = (CaseWhen) child;
+ // WHEN THEN
+ for (WhenClause whenClause : caseWhen.getWhenClauses()) {
+ conditionExps.add(whenClause.getOperand());
+ returnExps.add(whenClause.getResult());
+ }
+ // ELSE
+ returnExps.add(caseWhen.getDefaultValue().orElse(new NullLiteral()));
+ } else {
+ // currently, only IF and CASE WHEN are supported
+ returnExps.add(child);
+ }
+
+ // step 2: check condition expressions
+ for (Expression conditionExp : conditionExps) {
+ if (!containsAllColumn(conditionExp, ctx.keyNameToColumn.keySet())) {
+ return PreAggStatus.off(String.format("some columns in condition [%s] is not key.",
+ conditionExp.toSql()));
+ }
+ }
+
+ // step 3: check return expressions
+ // NOTE: now we just support SUM, MIN, MAX and COUNT DISTINCT
+ int returnExprValidateNum = 0;
+ for (Expression returnExp : returnExps) {
+ // ignore cast in return expr
+ while (returnExp instanceof Cast) {
+ returnExp = returnExp.child(0);
+ }
+ // now we only check simple return expressions
+ String exprName = returnExp.getExpressionName();
+ if (!returnExp.children().isEmpty()) {
+ return PreAggStatus.off(String.format("do not support compound expression [%s] in %s.",
+ returnExp.toSql(), matchingAggType));
+ }
+ if (ctx.keyNameToColumn.containsKey(exprName)) {
+ if (matchingAggType != AggregateType.MAX && matchingAggType != AggregateType.MIN
+ && (aggFunc instanceof Count && !aggFunc.isDistinct())) {
+ return PreAggStatus.off("agg on key column should be MAX, MIN or COUNT DISTINCT.");
+ }
+ }
+
+ if (matchingAggType == AggregateType.SUM) {
+ if ((ctx.valueNameToColumn.containsKey(exprName)
+ && ctx.valueNameToColumn.get(exprName).getAggregationType() == matchingAggType)
+ || returnExp.isZeroLiteral() || returnExp.isNullLiteral()) {
+ returnExprValidateNum++;
+ } else {
+ return PreAggStatus.off(String.format("SUM cant preagg for [%s].", aggFunc.toSql()));
+ }
+ } else if (matchingAggType == AggregateType.MAX || matchingAggType == AggregateType.MIN) {
+ if (ctx.keyNameToColumn.containsKey(exprName) || returnExp.isNullLiteral()
+ || (ctx.valueNameToColumn.containsKey(exprName)
+ && ctx.valueNameToColumn.get(exprName).getAggregationType() == matchingAggType)) {
+ returnExprValidateNum++;
+ } else {
+ return PreAggStatus.off(String.format("MAX/MIN cant preagg for [%s].", aggFunc.toSql()));
+ }
+ } else if (aggFunc.getName().equalsIgnoreCase("COUNT") && aggFunc.isDistinct()) {
+ if (ctx.keyNameToColumn.containsKey(exprName)
+ || returnExp.isZeroLiteral() || returnExp.isNullLiteral()) {
+ returnExprValidateNum++;
+ } else {
+ return PreAggStatus.off(String.format("COUNT DISTINCT cant preagg for [%s].", aggFunc.toSql()));
+ }
+ }
+ }
+ if (returnExprValidateNum == returnExps.size()) {
+ return PreAggStatus.on();
+ }
+ return PreAggStatus.off(String.format("cant preagg for [%s].", aggFunc.toSql()));
+ }
}
private static class CheckContext {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
index 1ce12fc0efa..048cae55f3d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
@@ -260,6 +260,10 @@ public abstract class Expression extends AbstractTreeNode<Expression> implements
}
}
+ public boolean isZeroLiteral() {
+ return this instanceof Literal && ((Literal) this).isZero();
+ }
+
public final Expression castTo(DataType targetType) throws AnalysisException {
return uncheckedCastTo(targetType);
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java
index 6ba6461922f..11c292e3a0b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java
@@ -366,4 +366,27 @@ public abstract class Literal extends Expression implements LeafExpression, Comp
public boolean isStringLikeLiteral() {
return dataType.isStringLikeType();
}
+
+ /** whether is ZERO value **/
+ public boolean isZero() {
+ if (isNullLiteral()) {
+ return false;
+ }
+ if (dataType.isSmallIntType() || dataType.isTinyIntType() || dataType.isIntegerType()) {
+ return getValue().equals(0);
+ } else if (dataType.isBigIntType()) {
+ return getValue().equals(0L);
+ } else if (dataType.isLargeIntType()) {
+ return getValue().equals(BigInteger.ZERO);
+ } else if (dataType.isFloatType()) {
+ return getValue().equals(0.0f);
+ } else if (dataType.isDoubleType()) {
+ return getValue().equals(0.0);
+ } else if (dataType.isDecimalV2Type()) {
+ return getValue().equals(BigDecimal.ZERO);
+ } else if (dataType.isDecimalV3Type()) {
+ return getValue().equals(BigDecimal.ZERO);
+ }
+ return false;
+ }
}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java b/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java
index 3de53090c9b..06d234c1916 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/planner/SingleNodePlanner.java
@@ -28,6 +28,7 @@ import org.apache.doris.analysis.AssertNumRowsElement;
import org.apache.doris.analysis.BaseTableRef;
import org.apache.doris.analysis.BinaryPredicate;
import org.apache.doris.analysis.CaseExpr;
+import org.apache.doris.analysis.CaseWhenClause;
import org.apache.doris.analysis.CastExpr;
import org.apache.doris.analysis.Expr;
import org.apache.doris.analysis.ExprSubstitutionMap;
@@ -77,6 +78,7 @@ import org.apache.doris.thrift.TPushAggOp;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -653,19 +655,38 @@ public class SingleNodePlanner {
List<Column> conditionColumns = Lists.newArrayList();
if (!(aggExpr.getChild(0) instanceof SlotRef)) {
Expr child = aggExpr.getChild(0);
- if ((child instanceof CastExpr) && (child.getChild(0) instanceof SlotRef)) {
- if (child.getType().isNumericType()
- && child.getChild(0).getType().isNumericType()) {
- returnColumns.add(((SlotRef) child.getChild(0)).getDesc().getColumn());
- } else {
- turnOffReason = "aggExpr.getChild(0)["
+
+ // ignore cast
+ boolean castReturnExprValidate = true;
+ while (child instanceof CastExpr) {
+ if (child.getChild(0) instanceof SlotRef) {
+ if (child.getType().isNumericType() && child.getChild(0).getType().isNumericType()) {
+ returnColumns.add(((SlotRef) child.getChild(0)).getDesc().getColumn());
+ } else {
+ turnOffReason = "aggExpr.getChild(0)["
+ aggExpr.getChild(0).toSql()
+ "] is not Numeric CastExpr";
- aggExprValidate = false;
- break;
+ castReturnExprValidate = false;
+ break;
+ }
}
- } else if (aggExpr.getChild(0) instanceof CaseExpr) {
- CaseExpr caseExpr = (CaseExpr) aggExpr.getChild(0);
+ child = child.getChild(0);
+ }
+ if (!castReturnExprValidate) {
+ aggExprValidate = false;
+ break;
+ }
+ // convert IF to CASE WHEN.
+ // For example:
+ // IF(a > 1, 1, 0) -> CASE WHEN a > 1 THEN 1 ELSE 0 END
+ if (child instanceof FunctionCallExpr && ((FunctionCallExpr) child)
+ .getFnName().getFunction().equalsIgnoreCase("IF")) {
+ Preconditions.checkArgument(child.getChildren().size() == 3);
+ CaseWhenClause caseWhenClause = new CaseWhenClause(child.getChild(0), child.getChild(1));
+ child = new CaseExpr(ImmutableList.of(caseWhenClause), child.getChild(2));
+ }
+ if (child instanceof CaseExpr) {
+ CaseExpr caseExpr = (CaseExpr) child;
List<Expr> conditionExprs = caseExpr.getConditionExprs();
for (Expr conditionExpr : conditionExprs) {
List<TupleId> conditionTupleIds = Lists.newArrayList();
@@ -680,8 +701,14 @@ public class SingleNodePlanner {
boolean caseReturnExprValidate = true;
List<Expr> returnExprs = caseExpr.getReturnExprs();
for (Expr returnExpr : returnExprs) {
+ // ignore cast in return expr
+ while (returnExpr instanceof CastExpr) {
+ returnExpr = returnExpr.getChild(0);
+ }
if (returnExpr instanceof SlotRef) {
returnColumns.add(((SlotRef) returnExpr).getDesc().getColumn());
+ } else if (returnExpr.isNullLiteral() || returnExpr.isZeroLiteral()) {
+ // If then expr is NULL or Zero, open the preaggregation
} else {
turnOffReason = "aggExpr.getChild(0)[" + aggExpr.getChild(0).toSql()
+ "] is not SlotExpr";
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMvIndexTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMvIndexTest.java
index bc5a39cc744..83b969d9f12 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMvIndexTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMvIndexTest.java
@@ -1251,4 +1251,93 @@ class SelectMvIndexTest extends BaseMaterializedIndexSelectTest implements MemoP
Assertions.assertEquals(secondTableIndexName, scan1.getSelectedIndexName());
});
}
+
+ @Test
+ public void testSubExpressionsInAggregation() throws Exception {
+ createTable("CREATE TABLE db1.`test_pre_agg_tbl` (\n"
+ + " `k1` int,\n"
+ + " `k2` int,\n"
+ + " `k3` char,\n"
+ + " `k4` int,\n"
+ + " `k5` bigint,\n"
+ + " `k6` bigint,\n"
+ + " `v1` int SUM,\n"
+ + " `v2` bigint SUM,\n"
+ + " `v3` bigint MAX,\n"
+ + " `v4` bigint MIN,\n"
+ + " `v5` float SUM,\n"
+ + " `v6` double SUM,\n"
+ + " `v7` decimal SUM\n"
+ + ") ENGINE=OLAP\n"
+ + "AGGREGATE KEY(`k1`, `k2`, `k3`, `k4`, `k5`, `k6`)\n"
+ + "COMMENT \"OLAP\"\n"
+ + "DISTRIBUTED BY HASH(`k1`) BUCKETS 5\n"
+ + "PROPERTIES (\n"
+ + "\"replication_num\" = \"1\"\n"
+ + ");");
+ addRollup("alter table db1.test_pre_agg_tbl add rollup test_rollup(k1, k2, k3, v1, v2, v3, v4, v5, v6, v7)");
+
+ String sql1 = "select sum(case when k1 > 0 then v1 when k1 = 0 then 0 when k1 < 0 then v2 else 0 end),"
+ + "sum(case when k2 = 1 then 0 else v1 end),"
+ + "sum(case when k2 = 1 then null else v2 end),"
+ + "sum(case when k2 = 1 then null else v5 end),"
+ + "sum(case when k2 = 1 then null else v6 end),"
+ + "sum(case when k2 = 1 then null else v7 end)"
+ + "from db1.test_pre_agg_tbl";
+ // legacy planner
+ Assertions.assertTrue(getSQLPlanOrErrorMsg(sql1).contains(
+ "TABLE: db1.test_pre_agg_tbl(test_rollup), PREAGGREGATION: ON"));
+ // nereids planner
+ PlanChecker.from(connectContext)
+ .analyze(sql1)
+ .rewrite()
+ .matches(logicalOlapScan().when(scan -> {
+ Assertions.assertEquals("test_rollup", scan.getSelectedMaterializedIndexName().get());
+ Assertions.assertTrue(scan.getPreAggStatus().isOn());
+ return true;
+ }));
+
+ String sql2 = "select sum(case when k1 > 0 then v1 else 1 end) from db1.test_pre_agg_tbl";
+ // legacy planner
+ Assertions.assertTrue(getSQLPlanOrErrorMsg(sql2).contains("PREAGGREGATION: OFF"));
+ // nereids planner
+ PlanChecker.from(connectContext)
+ .analyze(sql2)
+ .rewrite()
+ .matches(logicalOlapScan().when(scan -> {
+ Assertions.assertEquals("test_pre_agg_tbl", scan.getSelectedMaterializedIndexName().get());
+ Assertions.assertTrue(scan.getPreAggStatus().isOff());
+ return true;
+ }));
+
+ String sql3 = "select max(case when k1 > 0 then v3 else null end),min(case when k1 > 0 then null else v4 end)"
+ + " from db1.test_pre_agg_tbl";
+ // legacy planner
+ Assertions.assertTrue(getSQLPlanOrErrorMsg(sql3).contains(
+ "TABLE: db1.test_pre_agg_tbl(test_rollup), PREAGGREGATION: ON"));
+ // nereids planner
+ PlanChecker.from(connectContext)
+ .analyze(sql3)
+ .rewrite()
+ .matches(logicalOlapScan().when(scan -> {
+ Assertions.assertEquals("test_rollup", scan.getSelectedMaterializedIndexName().get());
+ Assertions.assertTrue(scan.getPreAggStatus().isOn());
+ return true;
+ }));
+
+ String sql4 = "select count(distinct case when k1 > 0 then k1 else null end), "
+ + "count(distinct if(k2 < 0, null, k2)) from db1.test_pre_agg_tbl";
+ // legacy planner
+ Assertions.assertTrue(getSQLPlanOrErrorMsg(sql4).contains(
+ "TABLE: db1.test_pre_agg_tbl(test_rollup), PREAGGREGATION: ON"));
+ // nereids planner
+ PlanChecker.from(connectContext)
+ .analyze(sql4)
+ .rewrite()
+ .matches(logicalOlapScan().when(scan -> {
+ Assertions.assertEquals("test_rollup", scan.getSelectedMaterializedIndexName().get());
+ Assertions.assertTrue(scan.getPreAggStatus().isOn());
+ return true;
+ }));
+ }
}
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectRollupIndexTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectRollupIndexTest.java
index 9bf2e64ead0..706be618f98 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectRollupIndexTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/mv/SelectRollupIndexTest.java
@@ -242,7 +242,7 @@ class SelectRollupIndexTest extends BaseMaterializedIndexSelectTest implements M
.matches(logicalOlapScan().when(scan -> {
PreAggStatus preAgg = scan.getPreAggStatus();
Assertions.assertTrue(preAgg.isOff());
- Assertions.assertEquals("Slot((v1 + 1)) in sum((v1 + 1)) is neither key column nor value column.",
+ Assertions.assertEquals("do not support compound expression [(v1 + 1)] in SUM.",
preAgg.getOffReason());
return true;
}));
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org