You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2025/05/06 11:50:14 UTC

(doris) branch master updated: [fix](mtmv)before mtmv refresh,check column type if change (#49041)

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

morrysnow 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 3acb325c037 [fix](mtmv)before mtmv refresh,check column type if change (#49041)
3acb325c037 is described below

commit 3acb325c0374036a7fc3a801195c5fb189d99394
Author: zhangdong <zh...@selectdb.com>
AuthorDate: Tue May 6 19:50:07 2025 +0800

    [fix](mtmv)before mtmv refresh,check column type if change (#49041)
    
    - before mtmv refresh,check column type if change
    - fix tableMTMVs of fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java is not correct after replace MTMV/table
    - when MTMV is SCHEMA_CHANGE, will not refresh by commit
    - add more case
---
 .../main/java/org/apache/doris/alter/Alter.java    |  23 +-
 .../java/org/apache/doris/catalog/Database.java    |  37 +--
 .../main/java/org/apache/doris/catalog/Env.java    |  10 +-
 .../apache/doris/datasource/InternalCatalog.java   |   3 -
 .../apache/doris/job/extensions/mtmv/MTMVTask.java |  42 +++
 .../org/apache/doris/mtmv/MTMVHookService.java     |  10 +-
 .../java/org/apache/doris/mtmv/MTMVJobManager.java |   5 +-
 .../java/org/apache/doris/mtmv/MTMVPlanUtil.java   | 172 +++++++++++++
 .../org/apache/doris/mtmv/MTMVRelationManager.java |  17 +-
 .../java/org/apache/doris/mtmv/MTMVService.java    |  47 ++--
 .../plans/commands/info/AlterMTMVRenameInfo.java   |   6 +-
 .../plans/commands/info/AlterMTMVReplaceInfo.java  |  11 +-
 .../trees/plans/commands/info/CreateMTMVInfo.java  | 104 +-------
 .../commands/info/DistributionDescriptor.java      |   4 +
 .../org/apache/doris/mtmv/MTMVPlanUtilTest.java    | 282 +++++++++++++++++++++
 .../mtmv_p0/test_base_add_col_multi_level_mtmv.out | Bin 0 -> 403 bytes
 ...est_base_alter_col_comment_multi_level_mtmv.out | Bin 0 -> 443 bytes
 .../test_base_alter_col_type_multi_level_mtmv.out  | Bin 0 -> 452 bytes
 .../mtmv_p0/test_base_comment_multi_level_mtmv.out | Bin 0 -> 403 bytes
 .../test_base_drop_col_multi_level_mtmv.out        | Bin 0 -> 428 bytes
 .../mtmv_p0/test_base_drop_multi_level_mtmv.out    | Bin 0 -> 400 bytes
 .../mtmv_p0/test_base_recreate_on_commit_mtmv.out  | Bin 0 -> 288 bytes
 .../test_base_rename_col_multi_level_mtmv.out      | Bin 0 -> 436 bytes
 .../mtmv_p0/test_base_rename_multi_level_mtmv.out  | Bin 0 -> 408 bytes
 .../test_base_rename_mv_multi_level_mtmv.out       | Bin 0 -> 421 bytes
 .../mtmv_p0/test_base_rename_on_commit_mtmv.out    | Bin 0 -> 445 bytes
 .../test_base_rename_p_mv_multi_level_mtmv.out     | Bin 0 -> 429 bytes
 .../mtmv_p0/test_base_replace_multi_level_mtmv.out | Bin 0 -> 1075 bytes
 .../test_base_replace_mv_multi_level_mtmv.out      | Bin 0 -> 910 bytes
 .../mtmv_p0/test_base_replace_on_commit_mtmv.out   | Bin 0 -> 342 bytes
 .../data/mtmv_p0/test_column_type_mtmv.out         | Bin 0 -> 291 bytes
 .../test_base_add_col_multi_level_mtmv.groovy      | 140 ++++++++++
 ..._base_alter_col_comment_multi_level_mtmv.groovy | 140 ++++++++++
 ...est_base_alter_col_type_multi_level_mtmv.groovy | 140 ++++++++++
 .../test_base_comment_multi_level_mtmv.groovy      | 139 ++++++++++
 .../test_base_drop_col_multi_level_mtmv.groovy     | 141 +++++++++++
 .../mtmv_p0/test_base_drop_multi_level_mtmv.groovy | 152 +++++++++++
 .../test_base_recreate_on_commit_mtmv.groovy       |  86 +++++++
 .../test_base_rename_col_multi_level_mtmv.groovy   | 140 ++++++++++
 .../test_base_rename_multi_level_mtmv.groovy       | 141 +++++++++++
 .../test_base_rename_mv_multi_level_mtmv.groovy    | 148 +++++++++++
 .../mtmv_p0/test_base_rename_on_commit_mtmv.groovy | 105 ++++++++
 .../test_base_rename_p_mv_multi_level_mtmv.groovy  | 154 +++++++++++
 .../test_base_replace_multi_level_mtmv.groovy      | 180 +++++++++++++
 .../test_base_replace_mv_multi_level_mtmv.groovy   | 194 ++++++++++++++
 .../test_base_replace_on_commit_mtmv.groovy        | 100 ++++++++
 .../suites/mtmv_p0/test_column_type_mtmv.groovy    |  61 +++++
 .../suites/mtmv_p0/test_recreate_table_mtmv.groovy |   3 +
 48 files changed, 2756 insertions(+), 181 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
index 36df2983aa2..f4eff9fc005 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
@@ -71,6 +71,7 @@ import org.apache.doris.common.util.MetaLockUtils;
 import org.apache.doris.common.util.PropertyAnalyzer;
 import org.apache.doris.common.util.PropertyAnalyzer.RewriteProperty;
 import org.apache.doris.datasource.ExternalTable;
+import org.apache.doris.mtmv.BaseTableInfo;
 import org.apache.doris.nereids.trees.plans.commands.AlterSystemCommand;
 import org.apache.doris.nereids.trees.plans.commands.AlterTableCommand;
 import org.apache.doris.nereids.trees.plans.commands.CreateMaterializedViewCommand;
@@ -221,7 +222,8 @@ public class Alter {
 
         olapTable.checkNormalStateForAlter();
         boolean needProcessOutsideTableLock = false;
-        String oldTableName = olapTable.getName();
+        BaseTableInfo oldBaseTableInfo = new BaseTableInfo(olapTable);
+        Optional<BaseTableInfo> newBaseTableInfo = Optional.empty();
         if (currentAlterOps.checkTableStoragePolicy(alterClauses)) {
             String tableStoragePolicy = olapTable.getStoragePolicy();
             String currentStoragePolicy = currentAlterOps.getTableStoragePolicy(alterClauses);
@@ -328,8 +330,14 @@ public class Alter {
             }
         } else if (currentAlterOps.hasRenameOp()) {
             processRename(db, olapTable, alterClauses);
+            newBaseTableInfo = Optional.of(new BaseTableInfo(olapTable));
         } else if (currentAlterOps.hasReplaceTableOp()) {
             processReplaceTable(db, olapTable, alterClauses);
+            // after replace table, olapTable may still be old name, so need set it to new name
+            ReplaceTableClause clause = (ReplaceTableClause) alterClauses.get(0);
+            String newTblName = clause.getTblName();
+            newBaseTableInfo = Optional.of(new BaseTableInfo(olapTable));
+            newBaseTableInfo.get().setTableName(newTblName);
         } else if (currentAlterOps.contains(AlterOpType.MODIFY_TABLE_PROPERTY_SYNC)) {
             needProcessOutsideTableLock = true;
         } else if (currentAlterOps.contains(AlterOpType.MODIFY_DISTRIBUTION)) {
@@ -347,7 +355,8 @@ public class Alter {
             throw new DdlException("Invalid alter operations: " + currentAlterOps);
         }
         if (needChangeMTMVState(alterClauses)) {
-            Env.getCurrentEnv().getMtmvService().alterTable(olapTable, oldTableName);
+            Env.getCurrentEnv().getMtmvService()
+                    .alterTable(oldBaseTableInfo, newBaseTableInfo, currentAlterOps.hasReplaceTableOp());
         }
         return needProcessOutsideTableLock;
     }
@@ -810,11 +819,9 @@ public class Alter {
         // drop origin table and new table
         db.unregisterTable(oldTblName);
         db.unregisterTable(newTblName);
-
         // rename new table name to origin table name and add it to database
         newTbl.checkAndSetName(oldTblName, false);
         db.registerTable(newTbl);
-
         if (swapTable) {
             // rename origin table name to new table name and add it to database
             origTable.checkAndSetName(newTblName, false);
@@ -828,9 +835,13 @@ public class Alter {
             } else {
                 Env.getCurrentRecycleBin().recycleTable(db.getId(), origTable, isReplay, isForce, 0);
             }
-
             if (origTable.getType() == TableType.MATERIALIZED_VIEW) {
-                Env.getCurrentEnv().getMtmvService().deregisterMTMV((MTMV) origTable);
+                // Because the current dropMTMV will delete jobs related to materialized views,
+                // this method will maintain its own metadata for deleting jobs,
+                // so it cannot be called during playback
+                if (!isReplay) {
+                    Env.getCurrentEnv().getMtmvService().dropMTMV((MTMV) origTable);
+                }
             }
             Env.getCurrentEnv().getAnalysisManager().removeTableStats(origTable.getId());
         }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java
index 85f3cc3e79e..c354b172a19 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java
@@ -412,9 +412,7 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table>,
                 result = setIfNotExist;
                 isTableExist = true;
             } else {
-                idToTable.put(table.getId(), table);
-                lowerCaseToTableName.put(tableName.toLowerCase(), tableName);
-                nameToTable.put(table.getName(), table);
+                registerTable(table);
                 if (table.isTemporary()) {
                     Env.getCurrentEnv().registerTempTableAndSession(table);
                 }
@@ -426,8 +424,6 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table>,
                 }
                 if (table.getType() == TableType.ELASTICSEARCH) {
                     Env.getCurrentEnv().getEsRepository().registerTable((EsTable) table);
-                } else if (table.getType() == TableType.MATERIALIZED_VIEW) {
-                    Env.getCurrentEnv().getMtmvService().registerMTMV((MTMV) table, id);
                 }
             }
             return Pair.of(result, isTableExist);
@@ -451,6 +447,9 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table>,
             idToTable.put(olapTable.getId(), olapTable);
             nameToTable.put(olapTable.getName(), olapTable);
             lowerCaseToTableName.put(tableName.toLowerCase(), tableName);
+            if (olapTable instanceof MTMV) {
+                Env.getCurrentEnv().getMtmvService().registerMTMV((MTMV) olapTable, id);
+            }
         }
         olapTable.unmarkDropped();
         return result;
@@ -462,6 +461,9 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table>,
         }
         Table table = getTableNullable(tableName);
         if (table != null) {
+            if (table instanceof MTMV) {
+                Env.getCurrentEnv().getMtmvService().unregisterMTMV((MTMV) table);
+            }
             this.nameToTable.remove(tableName);
             this.lowerCaseToTableName.remove(tableName.toLowerCase());
             this.idToTable.remove(table.getId());
@@ -670,14 +672,7 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table>,
         int numTables = in.readInt();
         for (int i = 0; i < numTables; ++i) {
             Table table = Table.read(in);
-            table.setQualifiedDbName(fullQualifiedName);
-            if (table instanceof MTMV) {
-                Env.getCurrentEnv().getMtmvService().registerMTMV((MTMV) table, id);
-            }
-            String tableName = table.getName();
-            nameToTable.put(tableName, table);
-            idToTable.put(table.getId(), table);
-            lowerCaseToTableName.put(tableName.toLowerCase(), tableName);
+            registerTable(table);
         }
     }
 
@@ -686,12 +681,7 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table>,
         Preconditions.checkState(nameToTable.getClass() == ConcurrentHashMap.class,
                                  "nameToTable should be ConcurrentMap");
         nameToTable.forEach((tn, tb) -> {
-            tb.setQualifiedDbName(fullQualifiedName);
-            if (tb instanceof MTMV) {
-                Env.getCurrentEnv().getMtmvService().registerMTMV((MTMV) tb, id);
-            }
-            idToTable.put(tb.getId(), tb);
-            lowerCaseToTableName.put(tn.toLowerCase(), tn);
+            registerTable(tb);
         });
 
         if (Env.getCurrentEnvJournalVersion() >= FeMetaVersion.VERSION_105) {
@@ -765,14 +755,7 @@ public class Database extends MetaObject implements Writable, DatabaseIf<Table>,
         int numTables = in.readInt();
         for (int i = 0; i < numTables; ++i) {
             Table table = Table.read(in);
-            table.setQualifiedDbName(fullQualifiedName);
-            if (table instanceof MTMV) {
-                Env.getCurrentEnv().getMtmvService().registerMTMV((MTMV) table, id);
-            }
-            String tableName = table.getName();
-            nameToTable.put(tableName, table);
-            idToTable.put(table.getId(), table);
-            lowerCaseToTableName.put(tableName.toLowerCase(), tableName);
+            registerTable(table);
         }
 
         // read quota
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
index d208d4071c2..4ec9c37798e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
@@ -5028,6 +5028,14 @@ public class Env {
                     throw new DdlException("Table name[" + newTableName + "] is already used (in restoring)");
                 }
 
+                if (table.isManagedTable()) {
+                    // If not checked first, execute db.unregisterTable first,
+                    // and then check the name in setName, it cannot guarantee atomicity
+                    ((OlapTable) table).checkAndSetName(newTableName, true);
+                }
+
+                db.unregisterTable(oldTableName);
+
                 if (table.isManagedTable()) {
                     // olap table should also check if any rollup has same name as "newTableName"
                     ((OlapTable) table).checkAndSetName(newTableName, false);
@@ -5035,9 +5043,7 @@ public class Env {
                     table.setName(newTableName);
                 }
 
-                db.unregisterTable(oldTableName);
                 db.registerTable(table);
-
                 TableInfo tableInfo = TableInfo.createForTableRename(db.getId(), table.getId(), oldTableName,
                         newTableName);
                 editLog.logTableRename(tableInfo);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
index a2a09276b72..a98f68ac15c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
@@ -1053,9 +1053,6 @@ public class InternalCatalog implements CatalogIf<Database> {
         if (table.getType() == TableType.ELASTICSEARCH) {
             esRepository.deRegisterTable(table.getId());
         }
-        if (table.getType() == TableType.MATERIALIZED_VIEW) {
-            Env.getCurrentEnv().getMtmvService().deregisterMTMV((MTMV) table);
-        }
 
         Env.getCurrentEnv().getAnalysisManager().removeTableStats(table.getId());
         Env.getCurrentEnv().getDictionaryManager().dropTableDictionaries(db.getName(), table.getName());
diff --git a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java
index e6af2385b4b..5028145d53a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/job/extensions/mtmv/MTMVTask.java
@@ -22,6 +22,7 @@ import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.MTMV;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.TableIf;
+import org.apache.doris.catalog.Type;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.DdlException;
@@ -44,6 +45,7 @@ import org.apache.doris.mtmv.MTMVPartitionInfo.MTMVPartitionType;
 import org.apache.doris.mtmv.MTMVPartitionUtil;
 import org.apache.doris.mtmv.MTMVPlanUtil;
 import org.apache.doris.mtmv.MTMVRefreshContext;
+import org.apache.doris.mtmv.MTMVRefreshEnum.MTMVState;
 import org.apache.doris.mtmv.MTMVRefreshEnum.RefreshMethod;
 import org.apache.doris.mtmv.MTMVRefreshPartitionSnapshot;
 import org.apache.doris.mtmv.MTMVRelatedTableIf;
@@ -52,6 +54,7 @@ import org.apache.doris.mtmv.MTMVUtil;
 import org.apache.doris.nereids.StatementContext;
 import org.apache.doris.nereids.glue.LogicalPlanAdapter;
 import org.apache.doris.nereids.trees.plans.commands.UpdateMvByPartitionCommand;
+import org.apache.doris.nereids.trees.plans.commands.info.ColumnDefinition;
 import org.apache.doris.nereids.trees.plans.commands.info.TableNameInfo;
 import org.apache.doris.qe.AuditLogHelper;
 import org.apache.doris.qe.ConnectContext;
@@ -82,6 +85,7 @@ import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 public class MTMVTask extends AbstractTask {
     private static final Logger LOG = LogManager.getLogger(MTMVTask.class);
@@ -194,6 +198,11 @@ public class MTMVTask extends AbstractTask {
             // lock table order by id to avoid deadlock
             MetaLockUtils.readLockTables(tableIfs);
             try {
+                // if mtmv is schema_change, check if column type has changed
+                // If it's not in the schema_change state, the column type definitely won't change.
+                if (MTMVState.SCHEMA_CHANGE.equals(mtmv.getStatus().getState())) {
+                    checkColumnTypeIfChange(mtmv, ctx);
+                }
                 if (mtmv.getMvPartitionInfo().getPartitionType() != MTMVPartitionType.SELF_MANAGE) {
                     MTMVRelatedTableIf relatedTable = mtmv.getMvPartitionInfo().getRelatedTable();
                     if (!relatedTable.isValidRelatedTable()) {
@@ -247,6 +256,39 @@ public class MTMVTask extends AbstractTask {
         }
     }
 
+    private void checkColumnTypeIfChange(MTMV mtmv, ConnectContext ctx) throws JobException {
+        List<ColumnDefinition> currentColumnsDefinition = MTMVPlanUtil.generateColumnsBySql(mtmv.getQuerySql(), ctx,
+                mtmv.getMvPartitionInfo().getPartitionCol(),
+                mtmv.getDistributionColumnNames(), null, mtmv.getTableProperty().getProperties());
+        List<Column> currentColumns = currentColumnsDefinition.stream()
+                .map(ColumnDefinition::translateToCatalogStyle)
+                .collect(Collectors.toList());
+        List<Column> originalColumns = mtmv.getBaseSchema(true);
+        if (currentColumns.size() != originalColumns.size()) {
+            throw new JobException(String.format(
+                    "column length not equals, please check whether columns of base table have changed, "
+                            + "original length is: %s, current length is: %s",
+                    originalColumns.size(), currentColumns.size()));
+        }
+        for (int i = 0; i < originalColumns.size(); i++) {
+            if (!isTypeLike(originalColumns.get(i).getType(), currentColumns.get(i).getType())) {
+                throw new JobException(String.format(
+                        "column type not same, please check whether columns of base table have changed, "
+                                + "column name is: %s, original type is: %s, current type is: %s",
+                        originalColumns.get(i).getName(), originalColumns.get(i).getType().toSql(),
+                        currentColumns.get(i).getType().toSql()));
+            }
+        }
+    }
+
+    private boolean isTypeLike(Type type, Type typeOther) {
+        if (type.isStringType()) {
+            return typeOther.isStringType();
+        } else {
+            return type.equals(typeOther);
+        }
+    }
+
     private void executeWithRetry(Set<String> execPartitionNames, Map<TableIf, String> tableWithPartKey)
             throws Exception {
         int retryCount = 0;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVHookService.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVHookService.java
index e0edd06f8c9..0f2b04147e7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVHookService.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVHookService.java
@@ -29,6 +29,8 @@ import org.apache.doris.nereids.trees.plans.commands.info.RefreshMTMVInfo;
 import org.apache.doris.nereids.trees.plans.commands.info.ResumeMTMVInfo;
 import org.apache.doris.persist.AlterMTMV;
 
+import java.util.Optional;
+
 /**
  * Contains all operations that affect the mtmv
  */
@@ -63,7 +65,7 @@ public interface MTMVHookService {
      *
      * @param mtmv
      */
-    void deregisterMTMV(MTMV mtmv);
+    void unregisterMTMV(MTMV mtmv);
 
     /**
      * triggered when alter mtmv, only once
@@ -102,9 +104,11 @@ public interface MTMVHookService {
     /**
      * Triggered when baseTable is altered
      *
-     * @param table
+     * @param oldTableInfo info before alter
+     * @param newTableInfo info after alter
+     * @param isReplace
      */
-    void alterTable(Table table, String oldTableName);
+    void alterTable(BaseTableInfo oldTableInfo, Optional<BaseTableInfo> newTableInfo, boolean isReplace);
 
     /**
      * Triggered when pause mtmv
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVJobManager.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVJobManager.java
index 7ea3d9dc05f..752ff78fdaf 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVJobManager.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVJobManager.java
@@ -52,6 +52,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 import java.util.List;
+import java.util.Optional;
 
 /**
  * when do some operation, do something about job
@@ -144,7 +145,7 @@ public class MTMVJobManager implements MTMVHookService {
     }
 
     @Override
-    public void deregisterMTMV(MTMV mtmv) {
+    public void unregisterMTMV(MTMV mtmv) {
 
     }
 
@@ -189,7 +190,7 @@ public class MTMVJobManager implements MTMVHookService {
     }
 
     @Override
-    public void alterTable(Table table, String oldTableName) {
+    public void alterTable(BaseTableInfo oldTableInfo, Optional<BaseTableInfo> newTableInfo, boolean isReplace) {
 
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPlanUtil.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPlanUtil.java
index f6face9c3c9..8158564cd1d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPlanUtil.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVPlanUtil.java
@@ -19,11 +19,15 @@ package org.apache.doris.mtmv;
 
 import org.apache.doris.analysis.StatementBase;
 import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.catalog.AggregateType;
 import org.apache.doris.catalog.DatabaseIf;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.MTMV;
+import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.TableIf;
 import org.apache.doris.catalog.TableIf.TableType;
+import org.apache.doris.common.FeNameFormat;
+import org.apache.doris.common.util.PropertyAnalyzer;
 import org.apache.doris.datasource.CatalogIf;
 import org.apache.doris.mysql.privilege.Auth;
 import org.apache.doris.nereids.NereidsPlanner;
@@ -33,14 +37,33 @@ import org.apache.doris.nereids.glue.LogicalPlanAdapter;
 import org.apache.doris.nereids.parser.NereidsParser;
 import org.apache.doris.nereids.properties.PhysicalProperties;
 import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
+import org.apache.doris.nereids.trees.plans.commands.info.ColumnDefinition;
+import org.apache.doris.nereids.trees.plans.commands.info.SimpleColumnDefinition;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.types.AggStateType;
+import org.apache.doris.nereids.types.CharType;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.DecimalV2Type;
+import org.apache.doris.nereids.types.NullType;
+import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TinyIntType;
+import org.apache.doris.nereids.types.VarcharType;
+import org.apache.doris.nereids.types.coercion.CharacterType;
+import org.apache.doris.nereids.util.TypeCoercionUtils;
 import org.apache.doris.qe.ConnectContext;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import org.apache.commons.collections.CollectionUtils;
 
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import javax.annotation.Nullable;
@@ -151,4 +174,153 @@ public class MTMVPlanUtil {
             }
         }
     }
+
+    /**
+     * Derive the MTMV columns based on the query statement.
+     *
+     * @param querySql
+     * @param ctx
+     * @param partitionCol partition column name of MTMV
+     * @param distributionColumnNames distribution column names of MTMV
+     * @param simpleColumnDefinitions Use custom column names if provided (non-empty);
+     *         otherwise, auto-generate the column names.
+     * @param properties properties of MTMV, it determines whether row storage needs to be generated based on this.
+     * @return ColumnDefinitions of MTMV
+     */
+    public static List<ColumnDefinition> generateColumnsBySql(String querySql, ConnectContext ctx, String partitionCol,
+            Set<String> distributionColumnNames, List<SimpleColumnDefinition> simpleColumnDefinitions,
+            Map<String, String> properties) {
+        List<StatementBase> statements;
+        try {
+            statements = new NereidsParser().parseSQL(querySql);
+        } catch (Exception e) {
+            throw new ParseException("Nereids parse failed. " + e.getMessage());
+        }
+        StatementBase parsedStmt = statements.get(0);
+        LogicalPlan logicalPlan = ((LogicalPlanAdapter) parsedStmt).getLogicalPlan();
+        StatementContext original = ctx.getStatementContext();
+        try (StatementContext tempCtx = new StatementContext()) {
+            ctx.setStatementContext(tempCtx);
+            try {
+                NereidsPlanner planner = new NereidsPlanner(ctx.getStatementContext());
+                Plan plan = planner.planWithLock(logicalPlan, PhysicalProperties.ANY, ExplainLevel.ANALYZED_PLAN);
+                return generateColumns(plan, ctx, partitionCol, distributionColumnNames, simpleColumnDefinitions,
+                        properties);
+            } finally {
+                ctx.setStatementContext(original);
+            }
+        }
+    }
+
+    /**
+     * Derive the MTMV columns based on the analyzed plan.
+     *
+     * @param plan should be analyzed plan
+     * @param ctx
+     * @param partitionCol partition column name of MTMV
+     * @param distributionColumnNames distribution column names of MTMV
+     * @param simpleColumnDefinitions Use custom column names if provided (non-empty);
+     *         otherwise, auto-generate the column names.
+     * @param properties properties of MTMV, it determines whether row storage needs to be generated based on this.
+     * @return ColumnDefinitions of MTMV
+     */
+    public static List<ColumnDefinition> generateColumns(Plan plan, ConnectContext ctx, String partitionCol,
+            Set<String> distributionColumnNames, List<SimpleColumnDefinition> simpleColumnDefinitions,
+            Map<String, String> properties) {
+        List<ColumnDefinition> columns = Lists.newArrayList();
+        List<Slot> slots = plan.getOutput();
+        if (slots.isEmpty()) {
+            throw new org.apache.doris.nereids.exceptions.AnalysisException("table should contain at least one column");
+        }
+        if (!CollectionUtils.isEmpty(simpleColumnDefinitions) && simpleColumnDefinitions.size() != slots.size()) {
+            throw new org.apache.doris.nereids.exceptions.AnalysisException(
+                    "simpleColumnDefinitions size is not equal to the query's");
+        }
+        Set<String> colNames = Sets.newHashSet();
+        for (int i = 0; i < slots.size(); i++) {
+            String colName = CollectionUtils.isEmpty(simpleColumnDefinitions) ? slots.get(i).getName()
+                    : simpleColumnDefinitions.get(i).getName();
+            try {
+                FeNameFormat.checkColumnName(colName);
+            } catch (org.apache.doris.common.AnalysisException e) {
+                throw new org.apache.doris.nereids.exceptions.AnalysisException(e.getMessage(), e);
+            }
+            if (colNames.contains(colName)) {
+                throw new org.apache.doris.nereids.exceptions.AnalysisException("repeat cols:" + colName);
+            } else {
+                colNames.add(colName);
+            }
+            DataType dataType = getDataType(slots.get(i), i, ctx, partitionCol, distributionColumnNames);
+            // If datatype is AggStateType, AggregateType should be generic, or column definition check will fail
+            columns.add(new ColumnDefinition(
+                    colName,
+                    dataType,
+                    false,
+                    slots.get(i).getDataType() instanceof AggStateType ? AggregateType.GENERIC : null,
+                    slots.get(i).nullable(),
+                    Optional.empty(),
+                    CollectionUtils.isEmpty(simpleColumnDefinitions) ? null
+                            : simpleColumnDefinitions.get(i).getComment()));
+        }
+        // add a hidden column as row store
+        if (properties != null) {
+            try {
+                boolean storeRowColumn =
+                        PropertyAnalyzer.analyzeStoreRowColumn(Maps.newHashMap(properties));
+                if (storeRowColumn) {
+                    columns.add(ColumnDefinition.newRowStoreColumnDefinition(null));
+                }
+            } catch (Exception e) {
+                throw new org.apache.doris.nereids.exceptions.AnalysisException(e.getMessage(), e.getCause());
+            }
+        }
+        return columns;
+    }
+
+    /**
+     * generate DataType by Slot
+     * @param s
+     * @param i
+     * @param ctx
+     * @param partitionCol
+     * @param distributionColumnNames
+     * @return
+     */
+    public static DataType getDataType(Slot s, int i, ConnectContext ctx, String partitionCol,
+            Set<String> distributionColumnNames) {
+        DataType dataType = s.getDataType().conversion();
+        // first column can not be TEXT, should transfer to varchar
+        if (i == 0 && dataType.isStringType()) {
+            dataType = VarcharType.createVarcharType(ScalarType.MAX_VARCHAR_LENGTH);
+        } else {
+            dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
+                    NullType.class, TinyIntType.INSTANCE);
+            dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
+                    DecimalV2Type.class, DecimalV2Type.SYSTEM_DEFAULT);
+            if (s.isColumnFromTable()) {
+                // check if external table
+                if ((!((SlotReference) s).getTable().isPresent()
+                        || !((SlotReference) s).getTable().get().isManagedTable())) {
+                    if (s.getName().equals(partitionCol) || distributionColumnNames.contains(s.getName())) {
+                        // String type can not be used in partition/distributed column
+                        // so we replace it to varchar
+                        dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
+                                CharacterType.class, VarcharType.MAX_VARCHAR_TYPE);
+                    } else {
+                        dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
+                                CharacterType.class, StringType.INSTANCE);
+                    }
+                }
+            } else {
+                if (ctx.getSessionVariable().useMaxLengthOfVarcharInCtas) {
+                    // The calculation of columns that are not from the original table will become VARCHAR(65533)
+                    dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
+                            VarcharType.class, VarcharType.MAX_VARCHAR_TYPE);
+                    dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
+                            CharType.class, VarcharType.MAX_VARCHAR_TYPE);
+                }
+            }
+        }
+        return dataType;
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java
index 125b8ce38de..7858aa95277 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVRelationManager.java
@@ -46,6 +46,7 @@ import org.apache.logging.log4j.Logger;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.BiPredicate;
 
@@ -213,7 +214,7 @@ public class MTMVRelationManager implements MTMVHookService {
      * @param mtmv
      */
     @Override
-    public void deregisterMTMV(MTMV mtmv) {
+    public void unregisterMTMV(MTMV mtmv) {
         removeMTMV(new BaseTableInfo(mtmv));
     }
 
@@ -255,17 +256,15 @@ public class MTMVRelationManager implements MTMVHookService {
     /**
      * update mtmv status to `SCHEMA_CHANGE`
      *
-     * @param table
+     * @param isReplace
      */
     @Override
-    public void alterTable(Table table, String oldTableName) {
-        BaseTableInfo baseTableInfo = new BaseTableInfo(table);
-        baseTableInfo.setTableName(oldTableName);
-        if (table instanceof MTMV) {
-            removeMTMV(baseTableInfo);
-            refreshMTMVCache(((MTMV) table).getRelation(), new BaseTableInfo(table));
+    public void alterTable(BaseTableInfo oldTableInfo, Optional<BaseTableInfo> newTableInfo, boolean isReplace) {
+        // when replace, need deal two table
+        if (isReplace) {
+            processBaseTableChange(newTableInfo.get(), "The base table has been updated:");
         }
-        processBaseTableChange(baseTableInfo, "The base table has been updated:");
+        processBaseTableChange(oldTableInfo, "The base table has been updated:");
     }
 
     @Override
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVService.java b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVService.java
index 2a9b1618df8..2ee42c0aa2c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVService.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mtmv/MTMVService.java
@@ -45,6 +45,7 @@ import org.apache.logging.log4j.Logger;
 
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 
 public class MTMVService implements EventListener {
@@ -76,23 +77,23 @@ public class MTMVService implements EventListener {
     }
 
     public void registerMTMV(MTMV mtmv, Long dbId) {
-        Objects.requireNonNull(mtmv);
+        Objects.requireNonNull(mtmv, "mtmv can not be null");
         LOG.info("registerMTMV: " + mtmv.getName());
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.registerMTMV(mtmv, dbId);
         }
     }
 
-    public void deregisterMTMV(MTMV mtmv) {
-        Objects.requireNonNull(mtmv);
+    public void unregisterMTMV(MTMV mtmv) {
+        Objects.requireNonNull(mtmv, "mtmv can not be null");
         LOG.info("deregisterMTMV: " + mtmv.getName());
         for (MTMVHookService mtmvHookService : hooks.values()) {
-            mtmvHookService.deregisterMTMV(mtmv);
+            mtmvHookService.unregisterMTMV(mtmv);
         }
     }
 
     public void createMTMV(MTMV mtmv) throws DdlException, AnalysisException {
-        Objects.requireNonNull(mtmv);
+        Objects.requireNonNull(mtmv, "mtmv can not be null");
         LOG.info("createMTMV: " + mtmv.getName());
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.createMTMV(mtmv);
@@ -100,7 +101,7 @@ public class MTMVService implements EventListener {
     }
 
     public void dropMTMV(MTMV mtmv) throws DdlException {
-        Objects.requireNonNull(mtmv);
+        Objects.requireNonNull(mtmv, "mtmv can not be null");
         LOG.info("dropMTMV: " + mtmv.getName());
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.dropMTMV(mtmv);
@@ -108,8 +109,8 @@ public class MTMVService implements EventListener {
     }
 
     public void alterMTMV(MTMV mtmv, AlterMTMV alterMTMV) throws DdlException {
-        Objects.requireNonNull(mtmv);
-        Objects.requireNonNull(alterMTMV);
+        Objects.requireNonNull(mtmv, "mtmv can not be null");
+        Objects.requireNonNull(alterMTMV, "alterMTMV can not be null");
         LOG.info("alterMTMV, mtmvName: {}, AlterMTMV: {}", mtmv.getName(), alterMTMV);
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.alterMTMV(mtmv, alterMTMV);
@@ -117,7 +118,7 @@ public class MTMVService implements EventListener {
     }
 
     public void refreshMTMV(RefreshMTMVInfo info) throws DdlException, MetaNotFoundException, JobException {
-        Objects.requireNonNull(info);
+        Objects.requireNonNull(info, "info can not be null");
         LOG.info("refreshMTMV, RefreshMTMVInfo: {}", info);
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.refreshMTMV(info);
@@ -125,24 +126,26 @@ public class MTMVService implements EventListener {
     }
 
     public void dropTable(Table table) {
-        Objects.requireNonNull(table);
+        Objects.requireNonNull(table, "table can not be null");
         LOG.info("dropTable, tableName: {}", table.getName());
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.dropTable(table);
         }
     }
 
-    public void alterTable(Table table, String oldTableName) {
-        Objects.requireNonNull(table);
-        LOG.info("alterTable, tableName: {}", table.getName());
+    public void alterTable(BaseTableInfo oldTableInfo, Optional<BaseTableInfo> newTableInfo, boolean isReplace) {
+        Objects.requireNonNull(oldTableInfo, "oldTableInfo can not be null");
+        Objects.requireNonNull(newTableInfo, "newTableInfo can not be null");
+        LOG.info("alterTable, oldTableInfo: {}, newTableInfo: {}, isReplace: {}", oldTableInfo, newTableInfo,
+                isReplace);
         for (MTMVHookService mtmvHookService : hooks.values()) {
-            mtmvHookService.alterTable(table, oldTableName);
+            mtmvHookService.alterTable(oldTableInfo, newTableInfo, isReplace);
         }
     }
 
     public void refreshComplete(MTMV mtmv, MTMVRelation cache, MTMVTask task) {
-        Objects.requireNonNull(mtmv);
-        Objects.requireNonNull(task);
+        Objects.requireNonNull(mtmv, "mtmv can not be null");
+        Objects.requireNonNull(task, "task can not be null");
         LOG.info("refreshComplete: " + mtmv.getName());
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.refreshComplete(mtmv, cache, task);
@@ -150,7 +153,7 @@ public class MTMVService implements EventListener {
     }
 
     public void pauseMTMV(PauseMTMVInfo info) throws DdlException, MetaNotFoundException, JobException {
-        Objects.requireNonNull(info);
+        Objects.requireNonNull(info, "info can not be null");
         LOG.info("pauseMTMV, PauseMTMVInfo: {}", info);
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.pauseMTMV(info);
@@ -158,7 +161,7 @@ public class MTMVService implements EventListener {
     }
 
     public void resumeMTMV(ResumeMTMVInfo info) throws MetaNotFoundException, DdlException, JobException {
-        Objects.requireNonNull(info);
+        Objects.requireNonNull(info, "info can not be null");
         LOG.info("resumeMTMV, ResumeMTMVInfo: {}", info);
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.resumeMTMV(info);
@@ -166,7 +169,7 @@ public class MTMVService implements EventListener {
     }
 
     public void cancelMTMVTask(CancelMTMVTaskInfo info) throws MetaNotFoundException, DdlException, JobException {
-        Objects.requireNonNull(info);
+        Objects.requireNonNull(info, "info can not be null");
         LOG.info("cancelMTMVTask, CancelMTMVTaskInfo: {}", info);
         for (MTMVHookService mtmvHookService : hooks.values()) {
             mtmvHookService.cancelMTMVTask(info);
@@ -175,7 +178,7 @@ public class MTMVService implements EventListener {
 
     @Override
     public void processEvent(Event event) throws EventException {
-        Objects.requireNonNull(event);
+        Objects.requireNonNull(event, "event can not be null");
         if (!(event instanceof TableEvent)) {
             return;
         }
@@ -199,7 +202,7 @@ public class MTMVService implements EventListener {
             try {
                 // check if mtmv should trigger by event
                 MTMV mtmv = (MTMV) MTMVUtil.getTable(baseTableInfo);
-                if (canRefresh(mtmv, table)) {
+                if (shouldRefreshOnBaseTableDataChange(mtmv, table)) {
                     jobManager.onCommit(mtmv);
                 }
             } catch (Exception e) {
@@ -208,7 +211,7 @@ public class MTMVService implements EventListener {
         }
     }
 
-    private boolean canRefresh(MTMV mtmv, TableIf table) {
+    private boolean shouldRefreshOnBaseTableDataChange(MTMV mtmv, TableIf table) {
         TableName tableName = null;
         try {
             tableName = new TableName(table);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVRenameInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVRenameInfo.java
index 066342c3b2c..4e34c50321a 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVRenameInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVRenameInfo.java
@@ -22,10 +22,12 @@ import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.Table;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.FeNameFormat;
+import org.apache.doris.mtmv.BaseTableInfo;
 import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.qe.ConnectContext;
 
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * rename
@@ -60,7 +62,9 @@ public class AlterMTMVRenameInfo extends AlterMTMVInfo {
     public void run() throws DdlException {
         Database db = Env.getCurrentInternalCatalog().getDbOrDdlException(mvName.getDb());
         Table table = db.getTableOrDdlException(mvName.getTbl());
+        BaseTableInfo oldTableInfo = new BaseTableInfo(table);
         Env.getCurrentEnv().renameTable(db, table, newName);
-        Env.getCurrentEnv().getMtmvService().alterTable(table, mvName.getTbl());
+        BaseTableInfo newTableInfo = new BaseTableInfo(table);
+        Env.getCurrentEnv().getMtmvService().alterTable(oldTableInfo, Optional.of(newTableInfo), false);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVReplaceInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVReplaceInfo.java
index a640aca31f5..2b086599ff0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVReplaceInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/AlterMTMVReplaceInfo.java
@@ -25,12 +25,14 @@ import org.apache.doris.common.DdlException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.util.PropertyAnalyzer;
+import org.apache.doris.mtmv.BaseTableInfo;
 import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.qe.ConnectContext;
 
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * replace
@@ -90,12 +92,7 @@ public class AlterMTMVReplaceInfo extends AlterMTMVInfo {
         MTMV mtmv = (MTMV) db.getTableOrDdlException(mvName.getTbl(), TableType.MATERIALIZED_VIEW);
         MTMV newMtmv = (MTMV) db.getTableOrDdlException(newName, TableType.MATERIALIZED_VIEW);
         Env.getCurrentEnv().getAlterInstance().processReplaceTable(db, mtmv, newName, swapTable, true);
-        Env.getCurrentEnv().getMtmvService().alterTable(newMtmv, mvName.getTbl());
-        if (swapTable) {
-            Env.getCurrentEnv().getMtmvService().alterTable(mtmv, newName);
-        } else {
-            Env.getCurrentEnv().getMtmvService().dropMTMV(mtmv);
-            Env.getCurrentEnv().getMtmvService().dropTable(mtmv);
-        }
+        Env.getCurrentEnv().getMtmvService()
+                .alterTable(new BaseTableInfo(mtmv), Optional.of(new BaseTableInfo(newMtmv)), true);
     }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java
index 0cef570f050..8d2d0c390fc 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateMTMVInfo.java
@@ -24,12 +24,10 @@ import org.apache.doris.analysis.ListPartitionDesc;
 import org.apache.doris.analysis.PartitionDesc;
 import org.apache.doris.analysis.RangePartitionDesc;
 import org.apache.doris.analysis.TableName;
-import org.apache.doris.catalog.AggregateType;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.KeysType;
 import org.apache.doris.catalog.PartitionType;
-import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.TableIf;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.catalog.View;
@@ -61,8 +59,6 @@ import org.apache.doris.nereids.parser.NereidsParser;
 import org.apache.doris.nereids.properties.PhysicalProperties;
 import org.apache.doris.nereids.rules.exploration.mv.MaterializedViewUtils;
 import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.Slot;
-import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel;
 import org.apache.doris.nereids.trees.plans.commands.info.BaseViewInfo.AnalyzerForCreateView;
@@ -70,16 +66,7 @@ import org.apache.doris.nereids.trees.plans.commands.info.BaseViewInfo.PlanSlotF
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSink;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias;
-import org.apache.doris.nereids.types.AggStateType;
-import org.apache.doris.nereids.types.CharType;
 import org.apache.doris.nereids.types.DataType;
-import org.apache.doris.nereids.types.DecimalV2Type;
-import org.apache.doris.nereids.types.NullType;
-import org.apache.doris.nereids.types.StringType;
-import org.apache.doris.nereids.types.TinyIntType;
-import org.apache.doris.nereids.types.VarcharType;
-import org.apache.doris.nereids.types.coercion.CharacterType;
-import org.apache.doris.nereids.util.TypeCoercionUtils;
 import org.apache.doris.nereids.util.Utils;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.SessionVariable;
@@ -117,7 +104,7 @@ public class CreateMTMVInfo {
     private final LogicalPlan logicalQuery;
     private String querySql;
     private final MTMVRefreshInfo refreshInfo;
-    private final List<ColumnDefinition> columns = Lists.newArrayList();
+    private List<ColumnDefinition> columns = Lists.newArrayList();
     private final List<SimpleColumnDefinition> simpleColumnDefinitions;
     private final MTMVPartitionDefinition mvPartitionDefinition;
     private PartitionDesc partitionDesc;
@@ -292,7 +279,10 @@ public class CreateMTMVInfo {
             getRelation(baseTables, ctx);
             this.mvPartitionInfo = mvPartitionDefinition.analyzeAndTransferToMTMVPartitionInfo(planner);
             this.partitionDesc = generatePartitionDesc(ctx);
-            getColumns(plan, ctx, mvPartitionInfo.getPartitionCol(), distribution);
+            columns = MTMVPlanUtil.generateColumns(plan, ctx, mvPartitionInfo.getPartitionCol(),
+                    (distribution == null || CollectionUtils.isEmpty(distribution.getCols())) ? Sets.newHashSet()
+                            : Sets.newHashSet(distribution.getCols()),
+                    simpleColumnDefinitions, properties);
             analyzeKeys();
         }
     }
@@ -412,90 +402,6 @@ public class CreateMTMVInfo {
         }
     }
 
-    private void getColumns(Plan plan, ConnectContext ctx, String partitionCol, DistributionDescriptor distribution) {
-        List<Slot> slots = plan.getOutput();
-        if (slots.isEmpty()) {
-            throw new AnalysisException("table should contain at least one column");
-        }
-        if (!CollectionUtils.isEmpty(simpleColumnDefinitions) && simpleColumnDefinitions.size() != slots.size()) {
-            throw new AnalysisException("simpleColumnDefinitions size is not equal to the query's");
-        }
-        Set<String> colNames = Sets.newHashSet();
-        for (int i = 0; i < slots.size(); i++) {
-            String colName = CollectionUtils.isEmpty(simpleColumnDefinitions) ? slots.get(i).getName()
-                    : simpleColumnDefinitions.get(i).getName();
-            try {
-                FeNameFormat.checkColumnName(colName);
-            } catch (org.apache.doris.common.AnalysisException e) {
-                throw new AnalysisException(e.getMessage(), e);
-            }
-            if (colNames.contains(colName)) {
-                throw new AnalysisException("repeat cols:" + colName);
-            } else {
-                colNames.add(colName);
-            }
-            DataType dataType = getDataType(slots.get(i), i, ctx, partitionCol, distribution);
-            // If datatype is AggStateType, AggregateType should be generic, or column definition check will fail
-            columns.add(new ColumnDefinition(
-                    colName,
-                    dataType,
-                    false,
-                    slots.get(i).getDataType() instanceof AggStateType ? AggregateType.GENERIC : null,
-                    slots.get(i).nullable(),
-                    Optional.empty(),
-                    CollectionUtils.isEmpty(simpleColumnDefinitions) ? null
-                            : simpleColumnDefinitions.get(i).getComment()));
-        }
-        // add a hidden column as row store
-        if (properties != null) {
-            try {
-                boolean storeRowColumn =
-                        PropertyAnalyzer.analyzeStoreRowColumn(Maps.newHashMap(properties));
-                if (storeRowColumn) {
-                    columns.add(ColumnDefinition.newRowStoreColumnDefinition(null));
-                }
-            } catch (Exception e) {
-                throw new AnalysisException(e.getMessage(), e.getCause());
-            }
-        }
-    }
-
-    private DataType getDataType(Slot s, int i, ConnectContext ctx, String partitionCol,
-            DistributionDescriptor distribution) {
-        DataType dataType = s.getDataType().conversion();
-        if (i == 0 && dataType.isStringType()) {
-            dataType = VarcharType.createVarcharType(ScalarType.MAX_VARCHAR_LENGTH);
-        } else {
-            dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
-                    NullType.class, TinyIntType.INSTANCE);
-            dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
-                    DecimalV2Type.class, DecimalV2Type.SYSTEM_DEFAULT);
-            if (s.isColumnFromTable()) {
-                if ((!((SlotReference) s).getTable().isPresent()
-                        || !((SlotReference) s).getTable().get().isManagedTable())) {
-                    if (s.getName().equals(partitionCol) || (distribution != null && distribution.inDistributionColumns(
-                            s.getName()))) {
-                        // String type can not be used in partition/distributed column
-                        // so we replace it to varchar
-                        dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
-                                CharacterType.class, VarcharType.MAX_VARCHAR_TYPE);
-                    } else {
-                        dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
-                                CharacterType.class, StringType.INSTANCE);
-                    }
-                }
-            } else {
-                if (ctx.getSessionVariable().useMaxLengthOfVarcharInCtas) {
-                    dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
-                            VarcharType.class, VarcharType.MAX_VARCHAR_TYPE);
-                    dataType = TypeCoercionUtils.replaceSpecifiedType(dataType,
-                            CharType.class, VarcharType.MAX_VARCHAR_TYPE);
-                }
-            }
-        }
-        return dataType;
-    }
-
     /**
      * translate to catalog CreateMultiTableMaterializedViewStmt
      */
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DistributionDescriptor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DistributionDescriptor.java
index d93fef7add7..f315ec43eb2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DistributionDescriptor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/DistributionDescriptor.java
@@ -148,4 +148,8 @@ public class DistributionDescriptor {
         }
         return stringBuilder.toString();
     }
+
+    public List<String> getCols() {
+        return cols;
+    }
 }
diff --git a/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVPlanUtilTest.java b/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVPlanUtilTest.java
new file mode 100644
index 00000000000..110f457cd00
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/mtmv/MTMVPlanUtilTest.java
@@ -0,0 +1,282 @@
+// 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.mtmv;
+
+import org.apache.doris.catalog.Column;
+import org.apache.doris.catalog.TableIf;
+import org.apache.doris.common.Config;
+import org.apache.doris.common.util.PropertyAnalyzer;
+import org.apache.doris.nereids.sqltest.SqlTestBase;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.commands.info.ColumnDefinition;
+import org.apache.doris.nereids.trees.plans.commands.info.SimpleColumnDefinition;
+import org.apache.doris.nereids.types.BigIntType;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.DecimalV2Type;
+import org.apache.doris.nereids.types.NullType;
+import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.TinyIntType;
+import org.apache.doris.nereids.types.VarcharType;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import mockit.Expectations;
+import mockit.Mocked;
+import org.junit.Assert;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+public class MTMVPlanUtilTest extends SqlTestBase {
+
+    @Test
+    public void testGenerateColumnsBySql() throws Exception {
+        createTables(
+                "CREATE TABLE IF NOT EXISTS MTMVPlanUtilTestT1 (\n"
+                        + "    id varchar(10),\n"
+                        + "    score String\n"
+                        + ")\n"
+                        + "DUPLICATE KEY(id)\n"
+                        + "AUTO PARTITION BY LIST(`id`)\n"
+                        + "(\n"
+                        + ")\n"
+                        + "DISTRIBUTED BY HASH(id) BUCKETS 1\n"
+                        + "PROPERTIES (\n"
+                        + "  \"replication_num\" = \"1\"\n"
+                        + ")\n"
+        );
+
+        String querySql = "select * from T1";
+        List<ColumnDefinition> actual = MTMVPlanUtil.generateColumnsBySql(querySql, connectContext, null,
+                Sets.newHashSet(), Lists.newArrayList(),
+                Maps.newHashMap());
+        List<ColumnDefinition> expect = Lists.newArrayList(new ColumnDefinition("id", BigIntType.INSTANCE, true),
+                new ColumnDefinition("score", BigIntType.INSTANCE, true));
+        checkRes(expect, actual);
+
+        Map<String, String> properties = Maps.newHashMap();
+        properties.put(PropertyAnalyzer.PROPERTIES_STORE_ROW_COLUMN, "true");
+        actual = MTMVPlanUtil.generateColumnsBySql(querySql, connectContext, null,
+                Sets.newHashSet(), Lists.newArrayList(), properties);
+        expect = Lists.newArrayList(new ColumnDefinition("id", BigIntType.INSTANCE, true),
+                new ColumnDefinition("score", BigIntType.INSTANCE, true),
+                new ColumnDefinition(Column.ROW_STORE_COL, StringType.INSTANCE, false));
+        checkRes(expect, actual);
+
+        querySql = "select T1.id from T1 inner join T2 on T1.id = T2.id";
+        actual = MTMVPlanUtil.generateColumnsBySql(querySql, connectContext, null,
+                Sets.newHashSet(), Lists.newArrayList(),
+                Maps.newHashMap());
+        expect = Lists.newArrayList(new ColumnDefinition("id", BigIntType.INSTANCE, true));
+        checkRes(expect, actual);
+
+        querySql = "select id,sum(score) from T1 group by id";
+        actual = MTMVPlanUtil.generateColumnsBySql(querySql, connectContext, null,
+                Sets.newHashSet(), Lists.newArrayList(),
+                Maps.newHashMap());
+        expect = Lists.newArrayList(new ColumnDefinition("id", BigIntType.INSTANCE, true),
+                new ColumnDefinition("__sum_1", BigIntType.INSTANCE, true));
+        checkRes(expect, actual);
+
+        querySql = "select id,sum(score) from T1 group by id";
+        actual = MTMVPlanUtil.generateColumnsBySql(querySql, connectContext, null,
+                Sets.newHashSet(), Lists.newArrayList(new SimpleColumnDefinition("id", null),
+                        new SimpleColumnDefinition("sum_score", null)),
+                Maps.newHashMap());
+        expect = Lists.newArrayList(new ColumnDefinition("id", BigIntType.INSTANCE, true),
+                new ColumnDefinition("sum_score", BigIntType.INSTANCE, true));
+        checkRes(expect, actual);
+
+        querySql = "select * from MTMVPlanUtilTestT1";
+        actual = MTMVPlanUtil.generateColumnsBySql(querySql, connectContext, null,
+                Sets.newHashSet(), Lists.newArrayList(),
+                Maps.newHashMap());
+        expect = Lists.newArrayList(new ColumnDefinition("id", new VarcharType(10), true),
+                new ColumnDefinition("score", StringType.INSTANCE, true));
+        checkRes(expect, actual);
+
+        querySql = "select score from MTMVPlanUtilTestT1";
+        actual = MTMVPlanUtil.generateColumnsBySql(querySql, connectContext, null,
+                Sets.newHashSet(), Lists.newArrayList(),
+                Maps.newHashMap());
+        expect = Lists.newArrayList(
+                new ColumnDefinition("score", VarcharType.MAX_VARCHAR_TYPE, true));
+        checkRes(expect, actual);
+    }
+
+    private void checkRes(List<ColumnDefinition> expect, List<ColumnDefinition> actual) {
+        Assert.assertEquals(expect.size(), actual.size());
+        for (int i = 0; i < expect.size(); i++) {
+            Assert.assertEquals(expect.get(i).getName(), actual.get(i).getName());
+            Assert.assertEquals(expect.get(i).getType(), actual.get(i).getType());
+        }
+    }
+
+    @Test
+    public void testGetDataType(@Mocked SlotReference slot, @Mocked TableIf slotTable) {
+        new Expectations() {
+            {
+                slot.getDataType();
+                minTimes = 0;
+                result = StringType.INSTANCE;
+
+                slot.isColumnFromTable();
+                minTimes = 0;
+                result = true;
+
+                slot.getTable();
+                minTimes = 0;
+                result = Optional.empty();
+
+                slot.getName();
+                minTimes = 0;
+                result = "slot_name";
+            }
+        };
+        // test i=0
+        DataType dataType = MTMVPlanUtil.getDataType(slot, 0, connectContext, "pcol", Sets.newHashSet("dcol"));
+        Assert.assertEquals(VarcharType.MAX_VARCHAR_TYPE, dataType);
+
+        // test isColumnFromTable and is not managed table
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "pcol", Sets.newHashSet("dcol"));
+        Assert.assertEquals(StringType.INSTANCE, dataType);
+
+        // test is partitionCol
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "slot_name", Sets.newHashSet("dcol"));
+        Assert.assertEquals(VarcharType.MAX_VARCHAR_TYPE, dataType);
+
+        // test is partitdistribution Col
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "pcol", Sets.newHashSet("slot_name"));
+        Assert.assertEquals(VarcharType.MAX_VARCHAR_TYPE, dataType);
+        // test managed table
+        new Expectations() {
+            {
+                slot.getTable();
+                minTimes = 0;
+                result = Optional.of(slotTable);
+
+                slotTable.isManagedTable();
+                minTimes = 0;
+                result = true;
+            }
+        };
+
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "pcol", Sets.newHashSet("slot_name"));
+        Assert.assertEquals(StringType.INSTANCE, dataType);
+
+        // test is not column table
+        boolean originalUseMaxLengthOfVarcharInCtas = connectContext.getSessionVariable().useMaxLengthOfVarcharInCtas;
+        new Expectations() {
+            {
+                slot.getDataType();
+                minTimes = 0;
+                result = new VarcharType(10);
+
+                slot.isColumnFromTable();
+                minTimes = 0;
+                result = false;
+            }
+        };
+        connectContext.getSessionVariable().useMaxLengthOfVarcharInCtas = true;
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "pcol", Sets.newHashSet("slot_name"));
+        Assert.assertEquals(VarcharType.MAX_VARCHAR_TYPE, dataType);
+
+        connectContext.getSessionVariable().useMaxLengthOfVarcharInCtas = false;
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "pcol", Sets.newHashSet("slot_name"));
+        Assert.assertEquals(new VarcharType(10), dataType);
+
+        connectContext.getSessionVariable().useMaxLengthOfVarcharInCtas = originalUseMaxLengthOfVarcharInCtas;
+
+        // test null type
+        new Expectations() {
+            {
+                slot.getDataType();
+                minTimes = 0;
+                result = NullType.INSTANCE;
+            }
+        };
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "pcol", Sets.newHashSet("slot_name"));
+        Assert.assertEquals(TinyIntType.INSTANCE, dataType);
+
+        // test decimal type
+        new Expectations() {
+            {
+                slot.getDataType();
+                minTimes = 0;
+                result = DecimalV2Type.createDecimalV2Type(1, 1);
+            }
+        };
+        boolean originalEnableDecimalConversion = Config.enable_decimal_conversion;
+        Config.enable_decimal_conversion = false;
+        dataType = MTMVPlanUtil.getDataType(slot, 1, connectContext, "pcol", Sets.newHashSet("slot_name"));
+        Assert.assertEquals(DecimalV2Type.SYSTEM_DEFAULT, dataType);
+
+        Config.enable_decimal_conversion = originalEnableDecimalConversion;
+    }
+
+    @Test
+    public void testGenerateColumns(@Mocked SlotReference slot, @Mocked Plan plan) {
+        new Expectations() {
+            {
+                plan.getOutput();
+                minTimes = 0;
+                result = Lists.newArrayList();
+            }
+        };
+        // test slots is empty
+        Assertions.assertThrows(org.apache.doris.nereids.exceptions.AnalysisException.class, () ->
+                MTMVPlanUtil.generateColumns(plan, connectContext, null, null, null, null));
+
+        new Expectations() {
+            {
+                plan.getOutput();
+                minTimes = 0;
+                result = Lists.newArrayList(slot);
+            }
+        };
+
+        // test size of slots and SimpleColumnDefinitions is different
+        Assertions.assertThrows(org.apache.doris.nereids.exceptions.AnalysisException.class, () ->
+                MTMVPlanUtil.generateColumns(plan, connectContext, null, null,
+                        Lists.newArrayList(new SimpleColumnDefinition("col1", "c1"),
+                                new SimpleColumnDefinition("col2", "c2")), null));
+
+        // test name format
+        Assertions.assertThrows(org.apache.doris.nereids.exceptions.AnalysisException.class, () ->
+                MTMVPlanUtil.generateColumns(plan, connectContext, null, null,
+                        Lists.newArrayList(new SimpleColumnDefinition("", "c1")), null));
+
+        new Expectations() {
+            {
+                plan.getOutput();
+                minTimes = 0;
+                result = Lists.newArrayList(slot, slot);
+            }
+        };
+        // test repeat col name
+        Assertions.assertThrows(org.apache.doris.nereids.exceptions.AnalysisException.class, () ->
+                MTMVPlanUtil.generateColumns(plan, connectContext, null, null,
+                        Lists.newArrayList(new SimpleColumnDefinition("col1", "c1"),
+                                new SimpleColumnDefinition("col1", "c2")), null));
+    }
+}
diff --git a/regression-test/data/mtmv_p0/test_base_add_col_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_add_col_multi_level_mtmv.out
new file mode 100644
index 00000000000..8d04722a3d6
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_add_col_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_alter_col_comment_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_alter_col_comment_multi_level_mtmv.out
new file mode 100644
index 00000000000..1715233c26c
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_alter_col_comment_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_alter_col_type_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_alter_col_type_multi_level_mtmv.out
new file mode 100644
index 00000000000..10c71d60f7c
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_alter_col_type_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_comment_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_comment_multi_level_mtmv.out
new file mode 100644
index 00000000000..dec544860a3
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_comment_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_drop_col_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_drop_col_multi_level_mtmv.out
new file mode 100644
index 00000000000..c9a16bf56f6
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_drop_col_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_drop_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_drop_multi_level_mtmv.out
new file mode 100644
index 00000000000..f04ea1d8b30
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_drop_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_recreate_on_commit_mtmv.out b/regression-test/data/mtmv_p0/test_base_recreate_on_commit_mtmv.out
new file mode 100644
index 00000000000..c40f161d606
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_recreate_on_commit_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_rename_col_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_rename_col_multi_level_mtmv.out
new file mode 100644
index 00000000000..4976d963cd6
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_rename_col_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_rename_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_rename_multi_level_mtmv.out
new file mode 100644
index 00000000000..8bbccdee4ce
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_rename_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_rename_mv_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_rename_mv_multi_level_mtmv.out
new file mode 100644
index 00000000000..a275b2ec9db
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_rename_mv_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_rename_on_commit_mtmv.out b/regression-test/data/mtmv_p0/test_base_rename_on_commit_mtmv.out
new file mode 100644
index 00000000000..dddffa8c2f1
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_rename_on_commit_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_rename_p_mv_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_rename_p_mv_multi_level_mtmv.out
new file mode 100644
index 00000000000..2dfc8b7f831
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_rename_p_mv_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_replace_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_replace_multi_level_mtmv.out
new file mode 100644
index 00000000000..147506ca708
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_replace_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_replace_mv_multi_level_mtmv.out b/regression-test/data/mtmv_p0/test_base_replace_mv_multi_level_mtmv.out
new file mode 100644
index 00000000000..1fdd40d9270
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_replace_mv_multi_level_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_base_replace_on_commit_mtmv.out b/regression-test/data/mtmv_p0/test_base_replace_on_commit_mtmv.out
new file mode 100644
index 00000000000..e5bb84bf378
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_base_replace_on_commit_mtmv.out differ
diff --git a/regression-test/data/mtmv_p0/test_column_type_mtmv.out b/regression-test/data/mtmv_p0/test_column_type_mtmv.out
new file mode 100644
index 00000000000..442df2b235f
Binary files /dev/null and b/regression-test/data/mtmv_p0/test_column_type_mtmv.out differ
diff --git a/regression-test/suites/mtmv_p0/test_base_add_col_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_add_col_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..1d079661968
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_add_col_multi_level_mtmv.groovy
@@ -0,0 +1,140 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_add_col_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_add_col_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 varchar(33)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // add column
+    sql """
+        alter table ${tableName1} add COLUMN new_col INT AFTER k2;
+        """
+    assertEquals("FINISHED", getAlterColumnFinalState("${tableName1}"))
+    order_qt_add_col_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_add_col_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_add_col_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_add_col_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName1)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_rewrite_success_without_check_chosen(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_alter_col_comment_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_alter_col_comment_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..6bb2eba17ad
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_alter_col_comment_multi_level_mtmv.groovy
@@ -0,0 +1,140 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_alter_col_comment_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_alter_col_comment_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32),
+            k3 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 varchar(33)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a","a2");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // alter column comment
+    sql """
+        alter table ${tableName1} modify COLUMN k3 COMMENT 'new comment';
+        """
+    order_qt_add_col_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_add_col_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_add_col_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_add_col_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName1)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_rewrite_success_without_check_chosen(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_alter_col_type_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_alter_col_type_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..83abd73dde5
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_alter_col_type_multi_level_mtmv.groovy
@@ -0,0 +1,140 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_alter_col_type_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_alter_col_type_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32),
+            k3 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 varchar(33)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a","a2");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // rename column
+    sql """
+        alter table ${tableName1} modify COLUMN k3 VARCHAR(100);
+        """
+    order_qt_add_col_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_add_col_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_add_col_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_add_col_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_not_part_in(querySql, mvName1)
+    mv_not_part_in(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_comment_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_comment_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..5636c7dbcb4
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_comment_multi_level_mtmv.groovy
@@ -0,0 +1,139 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_comment_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_comment_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 varchar(33)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // alter comment
+    sql """
+        alter table ${tableName1} MODIFY COMMENT "new table comment";
+        """
+    order_qt_comment_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_comment_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_comment_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_comment_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName1)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_rewrite_success_without_check_chosen(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_drop_col_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_drop_col_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..3f0b77e6073
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_drop_col_multi_level_mtmv.groovy
@@ -0,0 +1,141 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_drop_col_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_drop_col_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32),
+            k3 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 varchar(33)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a","a2");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // drop column
+    sql """
+        alter table ${tableName1} drop COLUMN k3;
+        """
+    assertEquals("FINISHED", getAlterColumnFinalState("${tableName1}"))
+    order_qt_add_col_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_add_col_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_add_col_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_add_col_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_not_part_in(querySql, mvName1)
+    mv_not_part_in(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_drop_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_drop_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..e81f1799ec5
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_drop_multi_level_mtmv.groovy
@@ -0,0 +1,152 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_drop_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_drop_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k3 INT,
+            k4 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k3) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k3) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // drop t1
+    sql """drop table if exists `${tableName1}`"""
+    order_qt_drop_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_drop_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_drop_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_drop_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_not_part_in(querySql, mvName1)
+    mv_not_part_in(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_recreate_on_commit_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_recreate_on_commit_mtmv.groovy
new file mode 100644
index 00000000000..c2011952a52
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_recreate_on_commit_mtmv.groovy
@@ -0,0 +1,86 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_recreate_on_commit_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_recreate_on_commit_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName = "${suiteName}_mv"
+
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 INT
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,1);
+        """
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName}
+        BUILD DEFERRED REFRESH AUTO ON COMMIT
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_select_init "select * from ${mvName}"
+
+    // drop and recreate
+    sql """drop table if exists `${tableName1}`"""
+    order_qt_drop "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName}'"
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 INT
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+
+    sql """
+            INSERT INTO ${tableName1} VALUES(2,2);
+        """
+
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_recreate "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName}'"
+    order_qt_select_recreate "select * from ${mvName}"
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_rename_col_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_rename_col_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..2e803efa5d2
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_rename_col_multi_level_mtmv.groovy
@@ -0,0 +1,140 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_rename_col_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_rename_col_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32),
+            k3 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 varchar(33)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a","a2");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // rename column
+    sql """
+        alter table ${tableName1} rename COLUMN k3 k4;
+        """
+    order_qt_add_col_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_add_col_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_add_col_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_add_col_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_not_part_in(querySql, mvName1)
+    mv_not_part_in(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_rename_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_rename_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..0f967ec096a
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_rename_multi_level_mtmv.groovy
@@ -0,0 +1,141 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_rename_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_rename_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName1Rename = "${suiteName}_table1_rename"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k4 from ${tableName1Rename} t1 join ${tableName2} t2 on t1.k1=t2.k3;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName1Rename}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k3 INT,
+            k4 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k3) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k3) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // rename t1
+    sql """
+        ALTER TABLE ${tableName1} rename ${tableName1Rename};
+        """
+    order_qt_drop_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_drop_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_drop_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_drop_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_not_part_in(querySql, mvName1)
+    mv_not_part_in(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_rename_mv_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_rename_mv_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..db95b0e412c
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_rename_mv_multi_level_mtmv.groovy
@@ -0,0 +1,148 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_rename_mv_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_rename_mv_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName1Rename = "${suiteName}_mv1_rename"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName1Rename};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k3 INT,
+            k4 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k3) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k3) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // rename mv1
+    sql """
+        ALTER MATERIALIZED VIEW ${mvName1} rename ${mvName1Rename};
+        """
+    order_qt_rename_mv_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1Rename}'"
+    order_qt_rename_mv_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_rename_mv_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_rename_mv_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+    // rename table will rename default partition name, so will change to async
+    mv_not_part_in(querySql, mvName1Rename)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+
+    // after refresh,should can rewrite
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1Rename} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1Rename)
+    mv_rewrite_success_without_check_chosen(querySql, mvName1Rename)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_rename_on_commit_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_rename_on_commit_mtmv.groovy
new file mode 100644
index 00000000000..02aca18c0f3
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_rename_on_commit_mtmv.groovy
@@ -0,0 +1,105 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_rename_on_commit_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_rename_on_commit_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName = "${suiteName}_mv"
+
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 INT
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,1);
+        """
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName}
+        BUILD DEFERRED REFRESH AUTO ON COMMIT
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_select_init "select * from ${mvName}"
+
+    // rename and recreate
+    sql """
+        ALTER TABLE ${tableName1} rename ${tableName2};
+        """
+    order_qt_rename "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName}'"
+
+    sql """
+            INSERT INTO ${tableName2} VALUES(2,2);
+        """
+
+    // after rename, should not refresh auto
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_rename "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName}'"
+    order_qt_select_rename "select * from ${mvName}"
+
+    // create t1
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 INT
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+      sql """
+             INSERT INTO ${tableName1} VALUES(10,10);
+         """
+
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_recreate_auto "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName}'"
+    order_qt_select_recreate_auto "select * from ${mvName}"
+
+    // t2 should not trigger refresh
+    order_qt_before_trigger "select count(*)  from tasks('type'='mv') where MvName='${mvName}'"
+    sql """
+             INSERT INTO ${tableName2} VALUES(4,4);
+         """
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_after_trigger "select count(*)  from tasks('type'='mv') where MvName='${mvName}'"
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_rename_p_mv_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_rename_p_mv_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..e7ba67650f9
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_rename_p_mv_multi_level_mtmv.groovy
@@ -0,0 +1,154 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_rename_p_mv_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_rename_p_mv_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName1Rename = "${suiteName}_mv1_rename"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName1Rename};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        PARTITION BY LIST(`k1`)
+        (
+            PARTITION `p1` VALUES IN ('1'),
+            PARTITION `p2` VALUES IN ('2'),
+            PARTITION `p3` VALUES IN ('3')
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k3 INT,
+            k4 varchar(32)
+        )
+        PARTITION BY LIST(`k3`)
+        (
+            PARTITION `p1` VALUES IN ('1'),
+            PARTITION `p2` VALUES IN ('2'),
+            PARTITION `p3` VALUES IN ('3')
+        )
+        DISTRIBUTED BY HASH(k3) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        partition by(`k1`)
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k3) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // rename mv1
+    sql """
+        ALTER MATERIALIZED VIEW ${mvName1} rename ${mvName1Rename};
+        """
+    order_qt_rename_mv_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1Rename}'"
+    order_qt_rename_mv_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_rename_mv_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_rename_mv_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+    mv_rewrite_success_without_check_chosen(querySql, mvName1Rename)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+    mv_not_part_in(querySql, mvName1)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_replace_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_replace_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..d572a818a9b
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_replace_multi_level_mtmv.groovy
@@ -0,0 +1,180 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_replace_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_replace_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 varchar(33)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k2 as k3 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k1;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // replace t1
+    sql """
+        ALTER TABLE ${tableName1} REPLACE WITH TABLE ${tableName2} PROPERTIES('swap' = 'true');
+        """
+    order_qt_replace_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_replace_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_replace_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_replace_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+    mv_not_part_in(querySql, mvName2)
+    mv_not_part_in(querySql, mvName1)
+    mv_not_part_in(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    order_qt_refresh_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_refresh_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_refresh_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_refresh_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+
+    mv_rewrite_success_without_check_chosen(querySql, mvName1)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_rewrite_success_without_check_chosen(querySql, mvName4)
+
+    // replace t1 swap false
+    sql """
+        ALTER TABLE ${tableName1} REPLACE WITH TABLE ${tableName2} PROPERTIES('swap' = 'false');
+        """
+    order_qt_replace_t1_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_replace_t1_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_replace_t1_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_replace_t1_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_replace_mv_multi_level_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_replace_mv_multi_level_mtmv.groovy
new file mode 100644
index 00000000000..410f28afd02
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_replace_mv_multi_level_mtmv.groovy
@@ -0,0 +1,194 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_replace_mv_multi_level_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_replace_mv_multi_level_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName1 = "${suiteName}_mv1"
+    String mvName11 = "${suiteName}_mv11"
+    String mvName2 = "${suiteName}_mv2"
+    String mvName3 = "${suiteName}_mv3"
+    String mvName4 = "${suiteName}_mv4"
+    String querySql = "SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;";
+    sql """set enable_materialized_view_nest_rewrite = true;"""
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName1};"""
+    sql """drop materialized view if exists ${mvName11};"""
+    sql """drop materialized view if exists ${mvName2};"""
+    sql """drop materialized view if exists ${mvName3};"""
+    sql """drop materialized view if exists ${mvName4};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k3 INT,
+            k4 varchar(32)
+        )
+        DISTRIBUTED BY HASH(k3) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,"a");
+        """
+    sql """
+        INSERT INTO ${tableName2} VALUES(1,"b");
+    """
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName1}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName11}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName11} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName11)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName2}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k3) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName2};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName2)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName3}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${tableName1} t1 join ${tableName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName3} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName3)
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName4}
+        BUILD DEFERRED REFRESH AUTO ON MANUAL
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT t1.k1,t1.k2,t2.k4 from ${mvName1} t1 join ${mvName2} t2 on t1.k1=t2.k3;
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName4} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName4)
+
+    // replace mv1
+    sql """
+        ALTER MATERIALIZED VIEW ${mvName1} REPLACE WITH MATERIALIZED VIEW ${mvName11} PROPERTIES('swap' = 'true');;
+        """
+    order_qt_replace_true_mv_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_replace_true_mv_mv11 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName11}'"
+    order_qt_replace_true_mv_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_replace_true_mv_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_replace_true_mv_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+    // replace table will rename default partition name, so will change to async
+    mv_not_part_in(querySql, mvName1)
+    mv_not_part_in(querySql, mvName11)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+
+    // after refresh,should can rewrite
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+    mv_rewrite_success_without_check_chosen(querySql, mvName1)
+
+    // after refresh,should can rewrite
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName11} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName11)
+    mv_rewrite_success_without_check_chosen(querySql, mvName11)
+
+    // replace mv1
+    sql """
+        ALTER MATERIALIZED VIEW ${mvName1} REPLACE WITH MATERIALIZED VIEW ${mvName11} PROPERTIES('swap' = 'false');;
+        """
+    order_qt_replace_false_mv_mv1 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName1}'"
+    order_qt_replace_false_mv_mv11 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName11}'"
+    order_qt_replace_false_mv_mv2 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName2}'"
+    order_qt_replace_false_mv_mv3 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName3}'"
+    order_qt_replace_false_mv_mv4 "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName4}'"
+    // replace table will rename default partition name, so will change to async
+    mv_not_part_in(querySql, mvName1)
+    mv_rewrite_success_without_check_chosen(querySql, mvName2)
+    mv_rewrite_success_without_check_chosen(querySql, mvName3)
+    mv_not_part_in(querySql, mvName4)
+
+    // after refresh,should can rewrite
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName1} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName1)
+    mv_rewrite_success_without_check_chosen(querySql, mvName1)
+}
diff --git a/regression-test/suites/mtmv_p0/test_base_replace_on_commit_mtmv.groovy b/regression-test/suites/mtmv_p0/test_base_replace_on_commit_mtmv.groovy
new file mode 100644
index 00000000000..8e8c3f599b2
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_base_replace_on_commit_mtmv.groovy
@@ -0,0 +1,100 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_base_replace_on_commit_mtmv","mtmv") {
+    String dbName = context.config.getDbNameByFile(context.file)
+    String suiteName = "test_base_replace_on_commit_mtmv"
+    String tableName1 = "${suiteName}_table1"
+    String tableName2 = "${suiteName}_table2"
+    String mvName = "${suiteName}_mv"
+
+    sql """drop table if exists `${tableName1}`"""
+    sql """drop table if exists `${tableName2}`"""
+    sql """drop materialized view if exists ${mvName};"""
+
+    sql """
+        CREATE TABLE ${tableName1}
+        (
+            k1 INT,
+            k2 INT
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+
+    sql """
+            INSERT INTO ${tableName1} VALUES(1,1);
+        """
+
+    sql """
+        CREATE TABLE ${tableName2}
+        (
+            k1 INT,
+            k2 INT
+        )
+        DISTRIBUTED BY HASH(k1) BUCKETS 2
+        PROPERTIES (
+            "replication_num" = "1"
+        );
+        """
+
+    sql """
+            INSERT INTO ${tableName2} VALUES(10,10);
+        """
+
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName}
+        BUILD DEFERRED REFRESH AUTO ON COMMIT
+        DISTRIBUTED BY hash(k1) BUCKETS 2
+        PROPERTIES (
+        'replication_num' = '1'
+        )
+        AS
+        SELECT * from ${tableName1};
+        """
+    sql """
+            REFRESH MATERIALIZED VIEW ${mvName} auto
+        """
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_select_init "select * from ${mvName}"
+
+    // replace
+    sql """
+        ALTER TABLE ${tableName1} REPLACE WITH TABLE ${tableName2} PROPERTIES('swap' = 'true');
+        """
+    order_qt_replace "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName}'"
+
+    sql """
+            INSERT INTO ${tableName1} VALUES(2,2);
+        """
+
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_replace "select Name,State,RefreshState  from mv_infos('database'='${dbName}') where Name='${mvName}'"
+    order_qt_select_replace "select * from ${mvName}"
+
+    // t2 should not trigger refresh
+    order_qt_before_trigger "select count(*)  from tasks('type'='mv') where MvName='${mvName}'"
+    sql """
+             INSERT INTO ${tableName2} VALUES(20,20);
+         """
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_after_trigger "select count(*)  from tasks('type'='mv') where MvName='${mvName}'"
+}
diff --git a/regression-test/suites/mtmv_p0/test_column_type_mtmv.groovy b/regression-test/suites/mtmv_p0/test_column_type_mtmv.groovy
new file mode 100644
index 00000000000..fdf03ad19da
--- /dev/null
+++ b/regression-test/suites/mtmv_p0/test_column_type_mtmv.groovy
@@ -0,0 +1,61 @@
+// 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.
+
+import org.junit.Assert;
+
+suite("test_column_type_mtmv","mtmv") {
+    String suiteName = "test_column_type_mtmv"
+    String tableName = "${suiteName}_table"
+    String mvName = "${suiteName}_mv"
+    sql """drop table if exists `${tableName}`"""
+    sql """drop materialized view if exists ${mvName};"""
+
+    sql """
+        CREATE TABLE ${tableName} (
+          `user_id` int NOT NULL,
+          class_id int,
+          `age` int NULL
+        ) ENGINE=OLAP
+        DUPLICATE KEY(`user_id`)
+        COMMENT 'OLAP'
+        DISTRIBUTED BY HASH(`user_id`) BUCKETS 2
+        PROPERTIES (
+        "replication_allocation" = "tag.location.default: 1"
+        );
+        """
+        sql """insert into ${tableName} values(1,1,1);"""
+    sql """
+        CREATE MATERIALIZED VIEW ${mvName}
+        BUILD IMMEDIATE REFRESH COMPLETE ON MANUAL
+        DISTRIBUTED BY RANDOM BUCKETS 2
+        PROPERTIES ('replication_num' = '1') AS
+        SELECT user_id,class_id,sum(age) from ${tableName} group by user_id,class_id;
+        """
+
+    waitingMTMVTaskFinishedByMvName(mvName)
+    order_qt_normal "select Name,State,RefreshState  from mv_infos('database'='regression_test_mtmv_p0') where Name='${mvName}'"
+    sql """alter table ${tableName} modify column class_id bigint;"""
+    assertEquals("FINISHED", getAlterColumnFinalState("${tableName}"))
+    order_qt_after_schema_change "select Name,State,RefreshState  from mv_infos('database'='regression_test_mtmv_p0') where Name='${mvName}'"
+    sql """
+         REFRESH MATERIALIZED VIEW ${mvName} auto;
+     """
+    def jobName = getJobName("regression_test_mtmv_p0", mvName);
+    waitingMTMVTaskFinishedNotNeedSuccess(jobName)
+    // can not be rewrite
+    order_qt_after_refresh "select Name,State,RefreshState  from mv_infos('database'='regression_test_mtmv_p0') where Name='${mvName}'"
+}
diff --git a/regression-test/suites/mtmv_p0/test_recreate_table_mtmv.groovy b/regression-test/suites/mtmv_p0/test_recreate_table_mtmv.groovy
index e9f7f339a0c..ffae7398e3a 100644
--- a/regression-test/suites/mtmv_p0/test_recreate_table_mtmv.groovy
+++ b/regression-test/suites/mtmv_p0/test_recreate_table_mtmv.groovy
@@ -81,6 +81,9 @@ suite("test_recreate_table_mtmv","mtmv") {
         """
     waitingMTMVTaskFinishedByMvName(mvName1);
     order_qt_mv1_recreate "SELECT * FROM ${mvName1}"
+     sql """
+            REFRESH MATERIALIZED VIEW ${mvName2} auto
+        """
     waitingMTMVTaskFinishedByMvName(mvName2);
     order_qt_mv2_recreate "SELECT * FROM ${mvName2}"
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org