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

starocean999 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


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

commit 649f9bc6837b57618ea17341ca716ceaffa3a1e0
Author: seawinde <149132972+seawi...@users.noreply.github.com>
AuthorDate: Fri Jun 14 11:15:53 2024 +0800

     [feature](mtmv) Support query rewrite by materialized view when query is 
aggregate and materialized view has no aggregate (#36278)
    
    ## Proposed changes
    
    Support query rewrite by materialized view when query is aggregate and
    materialized view has no aggregate
    this maybe improve query spped, because it can save expression
    evaluation by use the expression result in materialized view.
    
    this also support single table rewrite.
    
    For example as follwoing:
    mv def is:
    
    >            CREATE MATERIALIZED VIEW mv1
    >             BUILD IMMEDIATE REFRESH COMPLETE ON MANUAL
    >             DISTRIBUTED BY RANDOM BUCKETS 2
    >             PROPERTIES ('replication_num' = '1')
    >             AS
    > 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;
    
    
    the query as following can be rewritten by mv successfully
    
    >             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);
---
 .../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 ada72f04680..a5fb0b8736a 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
@@ -31,6 +31,7 @@ import 
org.apache.doris.nereids.rules.exploration.join.OuterJoinLAsscomProject;
 import 
org.apache.doris.nereids.rules.exploration.join.PushDownProjectThroughInnerOuterJoin;
 import 
org.apache.doris.nereids.rules.exploration.join.PushDownProjectThroughSemiJoin;
 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;
@@ -236,6 +237,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 62dc7840da9..bde86b61c29 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
@@ -396,6 +396,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: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to