This is an automated email from the ASF dual-hosted git repository.

morrysnow pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 1eb04cf5389  [feature](mtmv) Support query rewrite by materialized 
view when query is aggregate and materialized view has no aggregate (#36278) 
(#37497)
1eb04cf5389 is described below

commit 1eb04cf5389b2f63355fe1eee39ce15cb7ebb748
Author: seawinde <[email protected]>
AuthorDate: Thu Jul 11 10:54:50 2024 +0800

     [feature](mtmv) Support query rewrite by materialized view when query is 
aggregate and materialized view has no aggregate (#36278) (#37497)
    
    cherry-pick from master
    pr: #36278
    commitId: 649f9bc6
---
 .../org/apache/doris/nereids/rules/RuleSet.java    |   2 +
 .../org/apache/doris/nereids/rules/RuleType.java   |   6 +
 .../mv/AbstractMaterializedViewAggregateRule.java  | 116 ++++-
 .../mv/AbstractMaterializedViewJoinRule.java       |   2 +-
 .../mv/AbstractMaterializedViewRule.java           |  18 +-
 ...terializedViewAggregateOnNoneAggregateRule.java | 134 ++++++
 ...MaterializedViewFilterProjectAggregateRule.java |   2 +-
 ...MaterializedViewProjectFilterAggregateRule.java |   2 +-
 .../exploration/mv/MaterializedViewScanRule.java   |   2 +-
 .../mv/agg_on_none_agg/agg_on_none_agg.out         | 155 +++++++
 .../mv/agg_on_none_agg/agg_on_none_agg.groovy      | 488 +++++++++++++++++++++
 .../aggregate_without_roll_up.groovy               |   2 +-
 12 files changed, 890 insertions(+), 39 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
index cb6f6242da6..26920764d89 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
@@ -40,6 +40,7 @@ import 
org.apache.doris.nereids.rules.exploration.join.PushDownProjectThroughInn
 import 
org.apache.doris.nereids.rules.exploration.join.PushDownProjectThroughSemiJoin;
 import 
org.apache.doris.nereids.rules.exploration.join.SemiJoinSemiJoinTranspose;
 import 
org.apache.doris.nereids.rules.exploration.join.SemiJoinSemiJoinTransposeProject;
+import 
org.apache.doris.nereids.rules.exploration.mv.MaterializedViewAggregateOnNoneAggregateRule;
 import 
org.apache.doris.nereids.rules.exploration.mv.MaterializedViewAggregateRule;
 import 
org.apache.doris.nereids.rules.exploration.mv.MaterializedViewFilterAggregateRule;
 import 
org.apache.doris.nereids.rules.exploration.mv.MaterializedViewFilterJoinRule;
@@ -257,6 +258,7 @@ public class RuleSet {
             .add(MaterializedViewFilterProjectScanRule.INSTANCE)
             .add(MaterializedViewProjectScanRule.INSTANCE)
             .add(MaterializedViewProjectFilterScanRule.INSTANCE)
+            .add(MaterializedViewAggregateOnNoneAggregateRule.INSTANCE)
             .build();
 
     public static final List<Rule> DPHYP_REORDER_RULES = 
ImmutableList.<Rule>builder()
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 d8fd26c7949..9510dca0f48 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
@@ -390,6 +390,12 @@ public enum RuleType {
     MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE(RuleTypeClass.EXPLORATION),
     MATERIALIZED_VIEW_ONLY_AGGREGATE(RuleTypeClass.EXPLORATION),
 
+    
MATERIALIZED_VIEW_PROJECT_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION),
+    
MATERIALIZED_VIEW_FILTER_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION),
+    
MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION),
+    
MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION),
+    
MATERIALIZED_VIEW_ONLY_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION),
+
     MATERIALIZED_VIEW_FILTER_SCAN(RuleTypeClass.EXPLORATION),
     MATERIALIZED_VIEW_PROJECT_SCAN(RuleTypeClass.EXPLORATION),
     MATERIALIZED_VIEW_FILTER_PROJECT_SCAN(RuleTypeClass.EXPLORATION),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
index 997792f0f4c..53b0c29bde1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewAggregateRule.java
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.rules.exploration.mv;
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.CascadesContext;
 import org.apache.doris.nereids.rules.analysis.NormalizeRepeat;
+import 
org.apache.doris.nereids.rules.exploration.mv.AbstractMaterializedViewAggregateRule.AggregateExpressionRewriteContext.ExpressionRewriteMode;
 import 
org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext;
 import 
org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanSplitContext;
 import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping;
@@ -136,6 +137,27 @@ public abstract class 
AbstractMaterializedViewAggregateRule extends AbstractMate
                             
materializationContext.getShuttledExprToScanExprMapping(),
                             viewToQuerySlotMapping));
         }
+        return doRewriteQueryByView(queryStructInfo,
+                viewToQuerySlotMapping,
+                queryTopPlanAndAggPair,
+                tempRewritedPlan,
+                materializationContext,
+                ExpressionRewriteMode.EXPRESSION_DIRECT,
+                ExpressionRewriteMode.EXPRESSION_ROLL_UP);
+    }
+
+    /**
+     * Aggregate function and group by expression rewrite impl
+     */
+    protected LogicalAggregate<Plan> doRewriteQueryByView(
+            StructInfo queryStructInfo,
+            SlotMapping viewToQuerySlotMapping,
+            Pair<Plan, LogicalAggregate<Plan>> queryTopPlanAndAggPair,
+            Plan tempRewritedPlan,
+            MaterializationContext materializationContext,
+            ExpressionRewriteMode groupByMode,
+            ExpressionRewriteMode aggregateFunctionMode) {
+
         // try to roll up.
         // split the query top plan expressions to group expressions and 
functions, if can not, bail out.
         Pair<Set<? extends Expression>, Set<? extends Expression>> 
queryGroupAndFunctionPair
@@ -149,11 +171,12 @@ public abstract class 
AbstractMaterializedViewAggregateRule extends AbstractMate
         Map<Expression, Expression> mvExprToMvScanExprQueryBased =
                 
materializationContext.getShuttledExprToScanExprMapping().keyPermute(viewToQuerySlotMapping)
                         .flattenMap().get(0);
+        Plan queryTopPlan = queryStructInfo.getTopPlan();
         for (Expression topExpression : queryTopPlan.getOutput()) {
             if (queryTopPlanFunctionSet.contains(topExpression)) {
                 // if agg function, try to roll up and rewrite
                 Expression rollupedExpression = 
tryRewriteExpression(queryStructInfo, topExpression,
-                        mvExprToMvScanExprQueryBased, false, 
materializationContext,
+                        mvExprToMvScanExprQueryBased, aggregateFunctionMode, 
materializationContext,
                         "Query function roll up fail",
                         () -> String.format("queryExpression = %s,\n 
mvExprToMvScanExprQueryBased = %s",
                                 topExpression, mvExprToMvScanExprQueryBased));
@@ -164,7 +187,7 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
             } else {
                 // if group by dimension, try to rewrite
                 Expression rewrittenGroupByExpression = 
tryRewriteExpression(queryStructInfo, topExpression,
-                        mvExprToMvScanExprQueryBased, true, 
materializationContext,
+                        mvExprToMvScanExprQueryBased, groupByMode, 
materializationContext,
                         "View dimensions doesn't not cover the query 
dimensions",
                         () -> String.format("mvExprToMvScanExprQueryBased is 
%s,\n queryExpression is %s",
                                 mvExprToMvScanExprQueryBased, topExpression));
@@ -178,6 +201,7 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
                 finalGroupExpressions.add(groupByExpression);
             }
         }
+        LogicalAggregate<Plan> queryAggregate = queryTopPlanAndAggPair.value();
         List<Expression> queryGroupByExpressions = 
queryAggregate.getGroupByExpressions();
         // handle the scene that query top plan not use the group by in query 
bottom aggregate
         if (queryGroupByExpressions.size() != queryTopPlanGroupBySet.size()) {
@@ -186,7 +210,7 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
                     continue;
                 }
                 Expression rewrittenGroupByExpression = 
tryRewriteExpression(queryStructInfo, expression,
-                        mvExprToMvScanExprQueryBased, true, 
materializationContext,
+                        mvExprToMvScanExprQueryBased, groupByMode, 
materializationContext,
                         "View dimensions doesn't not cover the query 
dimensions in bottom agg ",
                         () -> String.format("mvExprToMvScanExprQueryBased is 
%s,\n expression is %s",
                                 mvExprToMvScanExprQueryBased, expression));
@@ -198,7 +222,7 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
                 finalGroupExpressions.add(groupByExpression);
             }
         }
-        if (queryContainsGroupSets) {
+        if (queryAggregate.getSourceRepeat().isPresent()) {
             // construct group sets for repeat
             List<List<Expression>> rewrittenGroupSetsExpressions = new 
ArrayList<>();
             List<List<Expression>> groupingSets = 
queryAggregate.getSourceRepeat().get().getGroupingSets();
@@ -209,7 +233,8 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
                     List<Expression> rewrittenGroupSetExpressions = new 
ArrayList<>();
                     for (Expression expression : groupingSet) {
                         Expression rewrittenGroupByExpression = 
tryRewriteExpression(queryStructInfo, expression,
-                                mvExprToMvScanExprQueryBased, true, 
materializationContext,
+                                mvExprToMvScanExprQueryBased, 
ExpressionRewriteMode.EXPRESSION_DIRECT,
+                                materializationContext,
                                 "View dimensions doesn't not cover the query 
group set dimensions",
                                 () -> 
String.format("mvExprToMvScanExprQueryBased is %s,\n queryExpression is %s",
                                         mvExprToMvScanExprQueryBased, 
expression));
@@ -232,14 +257,14 @@ public abstract class 
AbstractMaterializedViewAggregateRule extends AbstractMate
      * Try to rewrite query expression by view, contains both group by 
dimension and aggregate function
      */
     protected Expression tryRewriteExpression(StructInfo queryStructInfo, 
Expression queryExpression,
-            Map<Expression, Expression> mvShuttledExprToMvScanExprQueryBased, 
boolean isGroupBy,
+            Map<Expression, Expression> mvShuttledExprToMvScanExprQueryBased, 
ExpressionRewriteMode rewriteMode,
             MaterializationContext materializationContext, String 
summaryIfFail, Supplier<String> detailIfFail) {
         Expression queryFunctionShuttled = 
ExpressionUtils.shuttleExpressionWithLineage(
                 queryExpression,
                 queryStructInfo.getTopPlan(),
                 queryStructInfo.getTableBitSet());
         AggregateExpressionRewriteContext expressionRewriteContext = new 
AggregateExpressionRewriteContext(
-                isGroupBy, mvShuttledExprToMvScanExprQueryBased, 
queryStructInfo.getTopPlan(),
+                rewriteMode, mvShuttledExprToMvScanExprQueryBased, 
queryStructInfo.getTopPlan(),
                 queryStructInfo.getTableBitSet());
         Expression rewrittenExpression = 
queryFunctionShuttled.accept(AGGREGATE_EXPRESSION_REWRITER,
                 expressionRewriteContext);
@@ -344,7 +369,7 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
         return null;
     }
 
-    private Pair<Set<? extends Expression>, Set<? extends Expression>> 
topPlanSplitToGroupAndFunction(
+    protected Pair<Set<? extends Expression>, Set<? extends Expression>> 
topPlanSplitToGroupAndFunction(
             Pair<Plan, LogicalAggregate<Plan>> topPlanAndAggPair, StructInfo 
queryStructInfo) {
         LogicalAggregate<Plan> bottomQueryAggregate = 
topPlanAndAggPair.value();
         Set<Expression> groupByExpressionSet = new 
HashSet<>(bottomQueryAggregate.getGroupByExpressions());
@@ -377,7 +402,7 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
         return Pair.of(topGroupByExpressions, topFunctionExpressions);
     }
 
-    private Pair<Plan, LogicalAggregate<Plan>> 
splitToTopPlanAndAggregate(StructInfo structInfo) {
+    protected Pair<Plan, LogicalAggregate<Plan>> 
splitToTopPlanAndAggregate(StructInfo structInfo) {
         Plan topPlan = structInfo.getTopPlan();
         PlanSplitContext splitContext = new 
PlanSplitContext(Sets.newHashSet(LogicalAggregate.class));
         topPlan.accept(StructInfo.PLAN_SPLITTER, splitContext);
@@ -394,7 +419,7 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
      * slot reference equals currently.
      */
     @Override
-    protected boolean checkPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
+    protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
         PlanCheckContext checkContext = 
PlanCheckContext.of(SUPPORTED_JOIN_TYPE_SET);
         // if query or mv contains more then one top aggregate, should fail
         return structInfo.getTopPlan().accept(StructInfo.PLAN_PATTERN_CHECKER, 
checkContext)
@@ -414,17 +439,38 @@ public abstract class 
AbstractMaterializedViewAggregateRule extends AbstractMate
             if (!rewriteContext.isValid()) {
                 return aggregateFunction;
             }
-            Expression queryFunctionShuttled = 
ExpressionUtils.shuttleExpressionWithLineage(
-                    aggregateFunction,
-                    rewriteContext.getQueryTopPlan(),
-                    rewriteContext.getQueryTableBitSet());
-            Function rollupAggregateFunction = rollup(aggregateFunction, 
queryFunctionShuttled,
-                    rewriteContext.getMvExprToMvScanExprQueryBasedMapping());
-            if (rollupAggregateFunction == null) {
+            if 
(ExpressionRewriteMode.EXPRESSION_DIRECT.equals(rewriteContext.getExpressionRewriteMode()))
 {
                 rewriteContext.setValid(false);
                 return aggregateFunction;
             }
-            return rollupAggregateFunction;
+            Function rewrittenFunction;
+            if 
(ExpressionRewriteMode.EXPRESSION_ROLL_UP.equals(rewriteContext.getExpressionRewriteMode()))
 {
+                Expression queryFunctionShuttled = 
ExpressionUtils.shuttleExpressionWithLineage(
+                        aggregateFunction,
+                        rewriteContext.getQueryTopPlan(),
+                        rewriteContext.getQueryTableBitSet());
+                rewrittenFunction = rollup(aggregateFunction, 
queryFunctionShuttled,
+                        
rewriteContext.getMvExprToMvScanExprQueryBasedMapping());
+                if (rewrittenFunction == null) {
+                    rewriteContext.setValid(false);
+                    return aggregateFunction;
+                }
+                return rewrittenFunction;
+            }
+            if 
(ExpressionRewriteMode.EXPRESSION_DIRECT_ALL.equals(rewriteContext.getExpressionRewriteMode()))
 {
+                List<Expression> children = aggregateFunction.children();
+                List<Expression> rewrittenChildren = new ArrayList<>();
+                for (Expression child : children) {
+                    Expression rewrittenExpression = child.accept(this, 
rewriteContext);
+                    if (!rewriteContext.isValid()) {
+                        return aggregateFunction;
+                    }
+                    rewrittenChildren.add(rewrittenExpression);
+                }
+                return aggregateFunction.withChildren(rewrittenChildren);
+            }
+            rewriteContext.setValid(false);
+            return aggregateFunction;
         }
 
         @Override
@@ -474,7 +520,8 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
                 return expr;
             }
             // for group by expression try to get corresponding expression 
directly
-            if (rewriteContext.isOnlyContainGroupByExpression()
+            if 
((ExpressionRewriteMode.EXPRESSION_DIRECT.equals(rewriteContext.getExpressionRewriteMode())
+                    || 
ExpressionRewriteMode.EXPRESSION_DIRECT_ALL.equals(rewriteContext.getExpressionRewriteMode()))
                     && 
rewriteContext.getMvExprToMvScanExprQueryBasedMapping().containsKey(expr)) {
                 return 
rewriteContext.getMvExprToMvScanExprQueryBasedMapping().get(expr);
             }
@@ -499,15 +546,15 @@ public abstract class 
AbstractMaterializedViewAggregateRule extends AbstractMate
      */
     protected static class AggregateExpressionRewriteContext {
         private boolean valid = true;
-        private final boolean onlyContainGroupByExpression;
+        private final ExpressionRewriteMode expressionRewriteMode;
         private final Map<Expression, Expression> 
mvExprToMvScanExprQueryBasedMapping;
         private final Plan queryTopPlan;
         private final BitSet queryTableBitSet;
 
-        public AggregateExpressionRewriteContext(boolean 
onlyContainGroupByExpression,
+        public AggregateExpressionRewriteContext(ExpressionRewriteMode 
expressionRewriteMode,
                 Map<Expression, Expression> 
mvExprToMvScanExprQueryBasedMapping, Plan queryTopPlan,
                 BitSet queryTableBitSet) {
-            this.onlyContainGroupByExpression = onlyContainGroupByExpression;
+            this.expressionRewriteMode = expressionRewriteMode;
             this.mvExprToMvScanExprQueryBasedMapping = 
mvExprToMvScanExprQueryBasedMapping;
             this.queryTopPlan = queryTopPlan;
             this.queryTableBitSet = queryTableBitSet;
@@ -521,8 +568,8 @@ public abstract class AbstractMaterializedViewAggregateRule 
extends AbstractMate
             this.valid = valid;
         }
 
-        public boolean isOnlyContainGroupByExpression() {
-            return onlyContainGroupByExpression;
+        public ExpressionRewriteMode getExpressionRewriteMode() {
+            return expressionRewriteMode;
         }
 
         public Map<Expression, Expression> 
getMvExprToMvScanExprQueryBasedMapping() {
@@ -536,5 +583,26 @@ public abstract class 
AbstractMaterializedViewAggregateRule extends AbstractMate
         public BitSet getQueryTableBitSet() {
             return queryTableBitSet;
         }
+
+        /**
+         * The expression rewrite mode, which decide how the expression in 
query is rewritten by mv
+         */
+        protected enum ExpressionRewriteMode {
+            /**
+             * Try to use the expression in mv directly, and doesn't handle 
aggregate function
+             */
+            EXPRESSION_DIRECT,
+
+            /**
+             * Try to use the expression in mv directly, and try to rewrite 
the arguments in aggregate function except
+             * the aggregate function
+             */
+            EXPRESSION_DIRECT_ALL,
+
+            /**
+             * Try to roll up aggregate function
+             */
+            EXPRESSION_ROLL_UP
+        }
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
index 3bf037e0189..cc90a05d06d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewJoinRule.java
@@ -75,7 +75,7 @@ public abstract class AbstractMaterializedViewJoinRule 
extends AbstractMateriali
      * Join condition should be slot reference equals currently.
      */
     @Override
-    protected boolean checkPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
+    protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
         PlanCheckContext checkContext = 
PlanCheckContext.of(SUPPORTED_JOIN_TYPE_SET);
         return structInfo.getTopPlan().accept(StructInfo.PLAN_PATTERN_CHECKER, 
checkContext)
                 && !checkContext.isContainsTopAggregate();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
index b5377181126..74db83d7863 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/AbstractMaterializedViewRule.java
@@ -43,7 +43,6 @@ import 
org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Not;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
-import org.apache.doris.nereids.trees.expressions.VirtualSlotReference;
 import 
org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunction;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.NonNullable;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Nullable;
@@ -149,7 +148,7 @@ public abstract class AbstractMaterializedViewRule 
implements ExplorationRuleFac
         List<StructInfo> uncheckedStructInfos = 
MaterializedViewUtils.extractStructInfo(queryPlan, cascadesContext,
                 materializedViewTableSet);
         uncheckedStructInfos.forEach(queryStructInfo -> {
-            boolean valid = checkPattern(queryStructInfo, cascadesContext) && 
queryStructInfo.isValid();
+            boolean valid = checkQueryPattern(queryStructInfo, 
cascadesContext) && queryStructInfo.isValid();
             if (!valid) {
                 cascadesContext.getMaterializationContexts().forEach(ctx ->
                         ctx.recordFailReason(queryStructInfo, "Query struct 
info is invalid",
@@ -346,7 +345,7 @@ public abstract class AbstractMaterializedViewRule 
implements ExplorationRuleFac
         }
     }
 
-    private boolean needUnionRewrite(
+    protected boolean needUnionRewrite(
             Pair<Map<BaseTableInfo, Set<String>>, Map<BaseTableInfo, 
Set<String>>> invalidPartitions,
             CascadesContext cascadesContext) {
         return invalidPartitions != null
@@ -689,13 +688,17 @@ public abstract class AbstractMaterializedViewRule 
implements ExplorationRuleFac
     /**
      * Check the pattern of query or materializedView is supported or not.
      */
-    protected boolean checkPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
+    protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
         if (structInfo.getRelations().isEmpty()) {
             return false;
         }
         return true;
     }
 
+    protected boolean checkMaterializationPattern(StructInfo structInfo, 
CascadesContext cascadesContext) {
+        return checkQueryPattern(structInfo, cascadesContext);
+    }
+
     protected void recordIfRewritten(Plan plan, MaterializationContext 
context) {
         context.setSuccess(true);
         if (plan.getGroupExpression().isPresent()) {
@@ -708,11 +711,6 @@ public abstract class AbstractMaterializedViewRule 
implements ExplorationRuleFac
                 && 
context.alreadyRewrite(plan.getGroupExpression().get().getOwnerGroup().getGroupId());
     }
 
-    protected boolean isEmptyVirtualSlot(Expression expression) {
-        return expression instanceof VirtualSlotReference
-                && ((VirtualSlotReference) 
expression).getRealExpressions().isEmpty();
-    }
-
     // check mv plan is valid or not, this can use cache for performance
     private boolean isMaterializationValid(CascadesContext cascadesContext, 
MaterializationContext context) {
         long materializationId = 
context.getMaterializationQualifier().hashCode();
@@ -720,7 +718,7 @@ public abstract class AbstractMaterializedViewRule 
implements ExplorationRuleFac
                 materializationId);
         if (cachedCheckResult == null) {
             // need check in real time
-            boolean checkResult = checkPattern(context.getStructInfo(), 
cascadesContext);
+            boolean checkResult = 
checkMaterializationPattern(context.getStructInfo(), cascadesContext);
             if (!checkResult) {
                 context.recordFailReason(context.getStructInfo(),
                         "View struct info is invalid", () -> 
String.format("view plan is %s",
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateOnNoneAggregateRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateOnNoneAggregateRule.java
new file mode 100644
index 00000000000..21a8ea55857
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewAggregateOnNoneAggregateRule.java
@@ -0,0 +1,134 @@
+// 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.exploration.mv;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.Pair;
+import org.apache.doris.mtmv.BaseTableInfo;
+import org.apache.doris.nereids.CascadesContext;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import 
org.apache.doris.nereids.rules.exploration.mv.AbstractMaterializedViewAggregateRule.AggregateExpressionRewriteContext.ExpressionRewriteMode;
+import 
org.apache.doris.nereids.rules.exploration.mv.StructInfo.PlanCheckContext;
+import org.apache.doris.nereids.rules.exploration.mv.mapping.SlotMapping;
+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.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * MaterializedViewAggregateOnNoAggregateRule
+ */
+public class MaterializedViewAggregateOnNoneAggregateRule extends 
AbstractMaterializedViewAggregateRule {
+
+    public static final MaterializedViewAggregateOnNoneAggregateRule INSTANCE =
+            new MaterializedViewAggregateOnNoneAggregateRule();
+
+    @Override
+    public List<Rule> buildRules() {
+        return ImmutableList.of(
+                
logicalFilter(logicalProject(logicalAggregate(any().when(LogicalPlan.class::isInstance))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            
LogicalFilter<LogicalProject<LogicalAggregate<Plan>>> root = ctx.root;
+                            return rewrite(root, ctx.cascadesContext);
+                        
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE_ON_NONE_AGGREGATE),
+                
logicalAggregate(any().when(LogicalPlan.class::isInstance)).thenApplyMultiNoThrow(ctx
 -> {
+                    LogicalAggregate<Plan> root = ctx.root;
+                    return rewrite(root, ctx.cascadesContext);
+                
}).toRule(RuleType.MATERIALIZED_VIEW_ONLY_AGGREGATE_ON_NONE_AGGREGATE),
+                
logicalProject(logicalFilter(logicalAggregate(any().when(LogicalPlan.class::isInstance))))
+                        .thenApplyMultiNoThrow(ctx -> {
+                            
LogicalProject<LogicalFilter<LogicalAggregate<Plan>>> root = ctx.root;
+                            return rewrite(root, ctx.cascadesContext);
+                        
}).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE_ON_NONE_AGGREGATE),
+                
logicalProject(logicalAggregate(any().when(LogicalPlan.class::isInstance))).thenApplyMultiNoThrow(
+                        ctx -> {
+                            LogicalProject<LogicalAggregate<Plan>> root = 
ctx.root;
+                            return rewrite(root, ctx.cascadesContext);
+                        
}).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_AGGREGATE_ON_NONE_AGGREGATE),
+                
logicalFilter(logicalAggregate(any().when(LogicalPlan.class::isInstance))).thenApplyMultiNoThrow(
+                        ctx -> {
+                            LogicalFilter<LogicalAggregate<Plan>> root = 
ctx.root;
+                            return rewrite(root, ctx.cascadesContext);
+                        
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE_ON_NONE_AGGREGATE));
+    }
+
+    @Override
+    protected boolean checkMaterializationPattern(StructInfo structInfo, 
CascadesContext cascadesContext) {
+        // any check result of join or scan is true, then return true
+        PlanCheckContext joinCheckContext = 
PlanCheckContext.of(SUPPORTED_JOIN_TYPE_SET);
+        boolean joinCheckResult = 
structInfo.getTopPlan().accept(StructInfo.PLAN_PATTERN_CHECKER, 
joinCheckContext)
+                && !joinCheckContext.isContainsTopAggregate();
+        if (joinCheckResult) {
+            return true;
+        }
+        PlanCheckContext scanCheckContext = 
PlanCheckContext.of(ImmutableSet.of());
+        return 
structInfo.getTopPlan().accept(StructInfo.SCAN_PLAN_PATTERN_CHECKER, 
scanCheckContext)
+                && !scanCheckContext.isContainsTopAggregate();
+    }
+
+    @Override
+    protected Pair<Map<BaseTableInfo, Set<String>>, Map<BaseTableInfo, 
Set<String>>> calcInvalidPartitions(
+            Plan queryPlan, Plan rewrittenPlan, AsyncMaterializationContext 
materializationContext,
+            CascadesContext cascadesContext) throws AnalysisException {
+        Pair<Map<BaseTableInfo, Set<String>>, Map<BaseTableInfo, Set<String>>> 
invalidPartitions
+                = super.calcInvalidPartitions(queryPlan, rewrittenPlan, 
materializationContext, cascadesContext);
+        if (needUnionRewrite(invalidPartitions, cascadesContext)) {
+            // if query use some invalid partition in mv, bail out
+            return null;
+        }
+        return invalidPartitions;
+    }
+
+    @Override
+    protected Plan rewriteQueryByView(MatchMode matchMode, StructInfo 
queryStructInfo, StructInfo viewStructInfo,
+            SlotMapping viewToQuerySlotMapping, Plan tempRewritedPlan, 
MaterializationContext materializationContext) {
+        // check the expression used in group by and group out expression in 
query
+        Pair<Plan, LogicalAggregate<Plan>> queryTopPlanAndAggPair = 
splitToTopPlanAndAggregate(queryStructInfo);
+        if (queryTopPlanAndAggPair == null) {
+            materializationContext.recordFailReason(queryStructInfo,
+                    "Split query to top plan and agg fail",
+                    () -> String.format("query plan = %s\n", 
queryStructInfo.getOriginalPlan().treeString()));
+            return null;
+        }
+        LogicalAggregate<Plan> queryAggregate = queryTopPlanAndAggPair.value();
+        boolean queryContainsGroupSets = 
queryAggregate.getSourceRepeat().isPresent();
+        if (queryContainsGroupSets) {
+            // doesn't support group sets momentarily
+            materializationContext.recordFailReason(queryStructInfo,
+                    "Query function roll up fail",
+                    () -> String.format("query aggregate = %s", 
queryAggregate.treeString()));
+            return null;
+        }
+        return doRewriteQueryByView(queryStructInfo,
+                viewToQuerySlotMapping,
+                queryTopPlanAndAggPair,
+                tempRewritedPlan,
+                materializationContext,
+                ExpressionRewriteMode.EXPRESSION_DIRECT_ALL,
+                ExpressionRewriteMode.EXPRESSION_DIRECT_ALL);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
index bd7437a7d90..eb7c9bf5f82 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewFilterProjectAggregateRule.java
@@ -44,6 +44,6 @@ public class MaterializedViewFilterProjectAggregateRule 
extends AbstractMaterial
                         .thenApplyMultiNoThrow(ctx -> {
                             
LogicalFilter<LogicalProject<LogicalAggregate<Plan>>> root = ctx.root;
                             return rewrite(root, ctx.cascadesContext);
-                        
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE));
+                        
}).toRule(RuleType.MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE));
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
index 906ca31b4c2..c83eedea2a1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewProjectFilterAggregateRule.java
@@ -43,6 +43,6 @@ public class MaterializedViewProjectFilterAggregateRule 
extends AbstractMaterial
                 
any().when(LogicalPlan.class::isInstance)))).thenApplyMultiNoThrow(ctx -> {
                     LogicalProject<LogicalFilter<LogicalAggregate<Plan>>> root 
= ctx.root;
                     return rewrite(root, ctx.cascadesContext);
-                }).toRule(RuleType.MATERIALIZED_VIEW_FILTER_AGGREGATE));
+                
}).toRule(RuleType.MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE));
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewScanRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewScanRule.java
index e2c3d89cb92..904c121ce9e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewScanRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewScanRule.java
@@ -76,7 +76,7 @@ public abstract class MaterializedViewScanRule extends 
AbstractMaterializedViewR
      * Join condition should be slot reference equals currently.
      */
     @Override
-    protected boolean checkPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
+    protected boolean checkQueryPattern(StructInfo structInfo, CascadesContext 
cascadesContext) {
         PlanCheckContext checkContext = PlanCheckContext.of(ImmutableSet.of());
         return 
structInfo.getTopPlan().accept(StructInfo.SCAN_PLAN_PATTERN_CHECKER, 
checkContext)
                 && !checkContext.isContainsTopAggregate();
diff --git 
a/regression-test/data/nereids_rules_p0/mv/agg_on_none_agg/agg_on_none_agg.out 
b/regression-test/data/nereids_rules_p0/mv/agg_on_none_agg/agg_on_none_agg.out
new file mode 100644
index 00000000000..55d8a524c6e
--- /dev/null
+++ 
b/regression-test/data/nereids_rules_p0/mv/agg_on_none_agg/agg_on_none_agg.out
@@ -0,0 +1,155 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !query1_0_before --
+1      o       10
+1      o       100
+2      o       1
+2      o       101
+2      o       11
+
+-- !query1_0_after --
+1      o       10
+1      o       100
+2      o       1
+2      o       101
+2      o       11
+
+-- !query1_1_before --
+1      o       59874.14171519782
+1      o       7.307059979368067E43
+2      o       2.6881171418161356E43
+2      o       22026.465794806718
+2      o       5.92097202766467E47
+
+-- !query1_1_after --
+1      o       59874.14171519782
+1      o       7.307059979368067E43
+2      o       2.6881171418161356E43
+2      o       22026.465794806718
+2      o       5.92097202766467E47
+
+-- !query1_3_before --
+1      o       59874.14171519782       4
+1      o       7.307059979368067E43    4
+2      o       2.6881171418161356E43   4
+2      o       22026.465794806718      4
+2      o       5.92097202766467E47     6
+
+-- !query1_3_after --
+1      o       59874.14171519782       4
+1      o       7.307059979368067E43    4
+2      o       2.6881171418161356E43   4
+2      o       22026.465794806718      4
+2      o       5.92097202766467E47     6
+
+-- !query2_0_before --
+1      o       1       10
+1      o       2       100
+2      o       1       1
+2      o       1       11
+2      o       2       101
+
+-- !query2_0_after --
+1      o       1       10
+1      o       2       100
+2      o       1       1
+2      o       1       11
+2      o       2       101
+
+-- !query2_1_before --
+1      o       1       10      3
+1      o       2       100     3
+2      o       1       1       3
+2      o       1       11      4
+2      o       2       101     3
+
+-- !query2_1_after --
+1      o       1       10      3
+1      o       2       100     3
+2      o       1       1       3
+2      o       1       11      4
+2      o       2       101     3
+
+-- !query3_0_before --
+1      o       10
+1      o       100
+2      o       1
+2      o       101
+2      o       11
+
+-- !query3_0_after --
+1      o       10
+1      o       100
+2      o       1
+2      o       101
+2      o       11
+
+-- !query3_1_before --
+1      o       100
+2      o       101
+
+-- !query3_1_after --
+1      o       100
+2      o       101
+
+-- !query3_2_before --
+1      o       100
+2      o       101
+
+-- !query3_2_after --
+1      o       100
+2      o       101
+
+-- !query3_3_before --
+1      o       10
+1      o       100
+2      o       1
+2      o       11
+
+-- !query3_3_after --
+1      o       10
+1      o       100
+2      o       1
+2      o       11
+
+-- !query4_0_before --
+1      o       100
+2      o       101
+
+-- !query4_0_after --
+1      o       100
+2      o       101
+
+-- !query4_1_before --
+1      o       100     3
+
+-- !query4_1_after --
+1      o       100     3
+
+-- !query5_0_before --
+1      11.50   10
+1      43.20   100
+2      20.00   1
+2      46.00   11
+2      57.40   101
+
+-- !query5_0_after --
+1      11.50   10
+1      43.20   100
+2      20.00   1
+2      46.00   11
+2      57.40   101
+
+-- !query5_1_before --
+1      11.50   10
+1      43.20   100
+2      20.00   1
+2      46.00   11
+2      57.40   101
+
+-- !query5_1_after --
+1      11.50   10
+1      43.20   100
+2      20.00   1
+2      46.00   11
+2      57.40   101
+
diff --git 
a/regression-test/suites/nereids_rules_p0/mv/agg_on_none_agg/agg_on_none_agg.groovy
 
b/regression-test/suites/nereids_rules_p0/mv/agg_on_none_agg/agg_on_none_agg.groovy
new file mode 100644
index 00000000000..2219354e417
--- /dev/null
+++ 
b/regression-test/suites/nereids_rules_p0/mv/agg_on_none_agg/agg_on_none_agg.groovy
@@ -0,0 +1,488 @@
+package mv.agg_on_none_agg
+// 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.
+
+suite("agg_on_none_agg") {
+    String db = context.config.getDbNameByFile(context.file)
+    sql "use ${db}"
+    sql "set runtime_filter_mode=OFF";
+    sql "SET ignore_shape_nodes='PhysicalDistribute,PhysicalProject'"
+
+    sql """
+    drop table if exists orders
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS orders  (
+      o_orderkey       INTEGER NOT NULL,
+      o_custkey        INTEGER NOT NULL,
+      o_orderstatus    CHAR(1) NOT NULL,
+      o_totalprice     DECIMALV3(15,2) NOT NULL,
+      o_orderdate      DATE NOT NULL,
+      o_orderpriority  CHAR(15) NOT NULL,  
+      o_clerk          CHAR(15) NOT NULL, 
+      o_shippriority   INTEGER NOT NULL,
+      O_COMMENT        VARCHAR(79) NOT NULL
+    )
+    DUPLICATE KEY(o_orderkey, o_custkey)
+    PARTITION BY RANGE(o_orderdate) (
+    PARTITION `day_2` VALUES LESS THAN ('2023-12-9'),
+    PARTITION `day_3` VALUES LESS THAN ("2023-12-11"),
+    PARTITION `day_4` VALUES LESS THAN ("2023-12-30")
+    )
+    DISTRIBUTED BY HASH(o_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    );
+    """
+
+    sql """
+    insert into orders values
+    (1, 1, 'o', 9.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (1, 1, 'o', 10.5, '2023-12-08', 'a', 'b', 1, 'yy'),
+    (2, 1, 'o', 11.5, '2023-12-09', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 12.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (3, 1, 'o', 33.5, '2023-12-10', 'a', 'b', 1, 'yy'),
+    (4, 2, 'o', 43.2, '2023-12-11', 'c','d',2, 'mm'),
+    (5, 2, 'o', 56.2, '2023-12-12', 'c','d',2, 'mi'),
+    (5, 2, 'o', 1.2, '2023-12-12', 'c','d',2, 'mi');  
+    """
+
+    sql """
+    drop table if exists lineitem
+    """
+
+    sql"""
+    CREATE TABLE IF NOT EXISTS lineitem (
+      l_orderkey    INTEGER NOT NULL,
+      l_partkey     INTEGER NOT NULL,
+      l_suppkey     INTEGER NOT NULL,
+      l_linenumber  INTEGER NOT NULL,
+      l_quantity    DECIMALV3(15,2) NOT NULL,
+      l_extendedprice  DECIMALV3(15,2) NOT NULL,
+      l_discount    DECIMALV3(15,2) NOT NULL,
+      l_tax         DECIMALV3(15,2) NOT NULL,
+      l_returnflag  CHAR(1) NOT NULL,
+      l_linestatus  CHAR(1) NOT NULL,
+      l_shipdate    DATE NOT NULL,
+      l_commitdate  DATE NOT NULL,
+      l_receiptdate DATE NOT NULL,
+      l_shipinstruct CHAR(25) NOT NULL,
+      l_shipmode     CHAR(10) NOT NULL,
+      l_comment      VARCHAR(44) NOT NULL
+    )
+    DUPLICATE KEY(l_orderkey, l_partkey, l_suppkey, l_linenumber)
+    PARTITION BY RANGE(l_shipdate) (
+    PARTITION `day_1` VALUES LESS THAN ('2023-12-9'),
+    PARTITION `day_2` VALUES LESS THAN ("2023-12-11"),
+    PARTITION `day_3` VALUES LESS THAN ("2023-12-30"))
+    DISTRIBUTED BY HASH(l_orderkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """ insert into lineitem values
+    (1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-08', '2023-12-09', 
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (2, 4, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-09', '2023-12-09', 
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (3, 2, 4, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-10', '2023-12-09', 
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (4, 3, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-12-11', '2023-12-09', 
'2023-12-10', 'a', 'b', 'yyyyyyyyy'),
+    (5, 2, 3, 6, 7.5, 8.5, 9.5, 10.5, 'k', 'o', '2023-12-12', '2023-12-12', 
'2023-12-13', 'c', 'd', 'xxxxxxxxx');
+    """
+
+    sql """
+    drop table if exists partsupp
+    """
+
+    sql """
+    CREATE TABLE IF NOT EXISTS partsupp (
+      ps_partkey     INTEGER NOT NULL,
+      ps_suppkey     INTEGER NOT NULL,
+      ps_availqty    INTEGER NOT NULL,
+      ps_supplycost  DECIMALV3(15,2)  NOT NULL,
+      ps_comment     VARCHAR(199) NOT NULL 
+    )
+    DUPLICATE KEY(ps_partkey, ps_suppkey)
+    DISTRIBUTED BY HASH(ps_partkey) BUCKETS 3
+    PROPERTIES (
+      "replication_num" = "1"
+    )
+    """
+
+    sql """
+    insert into partsupp values
+    (2, 3, 9, 10.01, 'supply1'),
+    (2, 3, 10, 11.01, 'supply2');
+    """
+
+    sql """analyze table orders with sync;"""
+    sql """analyze table lineitem with sync;"""
+    sql """analyze table partsupp with sync;"""
+
+    def check_rewrite_but_not_chose = { mv_sql, query_sql, mv_name ->
+
+        sql """DROP MATERIALIZED VIEW IF EXISTS ${mv_name}"""
+        sql"""
+        CREATE MATERIALIZED VIEW ${mv_name} 
+        BUILD IMMEDIATE REFRESH COMPLETE ON MANUAL
+        DISTRIBUTED BY RANDOM BUCKETS 2
+        PROPERTIES ('replication_num' = '1') 
+        AS ${mv_sql}
+        """
+
+        def job_name = getJobName(db, mv_name);
+        waitingMTMVTaskFinished(job_name)
+        explain {
+            sql("${query_sql}")
+            check {result ->
+                def splitResult = result.split("MaterializedViewRewriteFail")
+                splitResult.length == 2 ? splitResult[0].contains(mv_name) : 
false
+            }
+        }
+    }
+
+    // query used expression is in mv
+    def mv1_0 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders;
+             """
+    def query1_0 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders
+             group by
+             o_orderstatus,
+             bin(o_orderkey);
+            """
+    order_qt_query1_0_before "${query1_0}"
+    check_mv_rewrite_success(db, mv1_0, query1_0, "mv1_0")
+    order_qt_query1_0_after "${query1_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_0"""
+
+
+    def mv1_1 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             o_orderkey + 1
+             from orders;
+             """
+    def query1_1 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             exp(bin(o_orderkey + 1))
+             from orders
+             group by
+             o_orderstatus,
+             exp(bin(o_orderkey + 1));
+            """
+    order_qt_query1_1_before "${query1_1}"
+    check_mv_rewrite_success(db, mv1_1, query1_1, "mv1_1")
+    order_qt_query1_1_after "${query1_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_1"""
+
+    def mv1_3 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             o_orderkey + 1,
+             l_linenumber
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey;
+             """
+    def query1_3 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             exp(bin(o_orderkey + 1)),
+             l_linenumber
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey
+             group by
+             l_linenumber,
+             o_orderstatus,
+             exp(bin(o_orderkey + 1));
+            """
+    order_qt_query1_3_before "${query1_3}"
+    check_mv_rewrite_success(db, mv1_3, query1_3, "mv1_3")
+    order_qt_query1_3_after "${query1_3}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv1_3"""
+
+    // query use expression is not in mv
+    def mv2_0 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey),
+             l_linenumber
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey;
+             """
+    def query2_0 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             o_shippriority,
+             bin(o_orderkey)
+             from orders
+             group by
+             o_orderstatus,
+             bin(o_orderkey),
+             o_shippriority;
+            """
+    order_qt_query2_0_before "${query2_0}"
+    check_mv_rewrite_fail(db, mv2_0, query2_0, "mv2_0")
+    order_qt_query2_0_after "${query2_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv2_0"""
+
+
+    def mv2_1 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders;
+             """
+    def query2_1 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             o_shippriority,
+             bin(o_orderkey),
+             l_suppkey
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey
+             group by
+             o_orderstatus,
+             bin(o_orderkey),
+             o_shippriority,
+             l_suppkey;
+            """
+    order_qt_query2_1_before "${query2_1}"
+    check_mv_rewrite_fail(db, mv2_1, query2_1, "mv2_1")
+    order_qt_query2_1_after "${query2_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv2_1"""
+
+
+    // query use filter and view doesn't use filter
+    def mv3_0 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders;
+             """
+    def query3_0 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders
+             where o_orderstatus = 'o'
+             group by
+             o_orderstatus,
+             bin(o_orderkey);
+            """
+    order_qt_query3_0_before "${query3_0}"
+    check_mv_rewrite_success(db, mv3_0, query3_0, "mv3_0")
+    order_qt_query3_0_after "${query3_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_0"""
+
+
+    def mv3_1 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders;
+             """
+    def query3_1 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders
+             where o_shippriority = 2
+             group by
+             o_orderstatus,
+             bin(o_orderkey);
+            """
+    order_qt_query3_1_before "${query3_1}"
+    // the filter slot used in query can not be found from mv
+    check_mv_rewrite_fail(db, mv3_1, query3_1, "mv3_1")
+    order_qt_query3_1_after "${query3_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_1"""
+
+
+    def mv3_2 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders;
+             """
+    def query3_2 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end) as count_case,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders
+             where o_shippriority = 2
+             group by
+             o_orderstatus,
+             bin(o_orderkey)
+             having count_case > 0;
+            """
+    order_qt_query3_2_before "${query3_2}"
+    // the filter slot used in query can not be found from mv
+    check_mv_rewrite_fail(db, mv3_2, query3_2, "mv3_2")
+    order_qt_query3_2_after "${query3_2}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_2"""
+
+
+    def mv3_3 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey),
+             l_suppkey,
+             l_linenumber
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey;
+             """
+    def query3_3 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end) as count_case,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey
+             where l_linenumber = 4
+             group by
+             o_orderstatus,
+             bin(o_orderkey);
+            """
+    order_qt_query3_3_before "${query3_3}"
+    // the filter slot used in query can not be found from mv
+    check_mv_rewrite_success(db, mv3_3, query3_3, "mv3_3")
+    order_qt_query3_3_after "${query3_3}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv3_3"""
+
+
+
+    // both query and view use filter
+    def mv4_0 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders
+             where o_shippriority = 2;
+             """
+    def query4_0 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             bin(o_orderkey)
+             from orders
+             where o_shippriority = 2 and o_orderstatus = 'o'
+             group by
+             o_orderstatus,
+             bin(o_orderkey);
+            """
+    order_qt_query4_0_before "${query4_0}"
+    check_mv_rewrite_success(db, mv4_0, query4_0, "mv4_0")
+    order_qt_query4_0_after "${query4_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv4_0"""
+
+
+    def mv4_1 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             bin(o_orderkey),
+             l_partkey
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey
+             where o_shippriority = 2 and l_linenumber = 4;
+             """
+    def query4_1 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             o_orderstatus,
+             bin(o_orderkey),
+             l_partkey
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey
+             where o_shippriority = 2 and o_orderstatus = 'o' and l_linenumber 
= 4
+             group by
+             o_orderstatus,
+             bin(o_orderkey),
+             l_partkey;
+            """
+    order_qt_query4_1_before "${query4_1}"
+    check_mv_rewrite_success(db, mv4_1, query4_1, "mv4_1")
+    order_qt_query4_1_after "${query4_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv4_1"""
+
+    // query use less dimension in select then group by
+
+    def mv5_0 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             o_totalprice,
+             bin(o_orderkey)
+             from orders;
+             """
+    def query5_0 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             sum(o_totalprice),
+             bin(o_orderkey)
+             from orders
+             group by
+             o_orderstatus,
+             bin(o_orderkey);
+            """
+    order_qt_query5_0_before "${query5_0}"
+    check_mv_rewrite_success(db, mv5_0, query5_0, "mv5_0")
+    order_qt_query5_0_after "${query5_0}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv5_0"""
+
+
+
+    def mv5_1 = """
+             select case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end,
+             o_orderstatus,
+             o_totalprice,
+             bin(o_orderkey),
+             l_linenumber
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey;
+             """
+    def query5_1 = """
+             select
+             count(case when o_shippriority > 1 and o_orderkey IN (4, 5) then 
o_custkey else o_shippriority end),
+             sum(o_totalprice),
+             bin(o_orderkey)
+             from orders
+             left join lineitem on o_orderkey =  l_orderkey
+             group by
+             o_orderstatus,
+             bin(o_orderkey),
+             l_linenumber;
+            """
+    order_qt_query5_1_before "${query5_1}"
+    check_mv_rewrite_success(db, mv5_1, query5_1, "mv5_1")
+    order_qt_query5_1_after "${query5_1}"
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv5_1"""
+}
diff --git 
a/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy
 
b/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy
index 72a6144bcda..83842996c29 100644
--- 
a/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy
+++ 
b/regression-test/suites/nereids_rules_p0/mv/agg_without_roll_up/aggregate_without_roll_up.groovy
@@ -835,7 +835,7 @@ suite("aggregate_without_roll_up") {
     order_qt_query19_3_before "${query19_3}"
     check_mv_rewrite_success(db, mv19_3, query19_3, "mv19_3")
     order_qt_query19_3_after "${query19_3}"
-    sql """ DROP MATERIALIZED VIEW IF EXISTS mv19_0"""
+    sql """ DROP MATERIALIZED VIEW IF EXISTS mv19_3"""
 
 
     // without group, scalar aggregate


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to