You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by yo...@apache.org on 2023/01/31 05:51:09 UTC

[iotdb] 01/02: ready for test

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

yongzao pushed a commit to branch Manually_control_RegionGroup_extension_in_creation_process
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 0b6ef5e4fa998b137d0db023eac751cfbefe0a25
Author: YongzaoDan <53...@qq.com>
AuthorDate: Tue Jan 31 12:12:55 2023 +0800

    ready for test
---
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |   2 +-
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |   8 ++
 .../iotdb/confignode/conf/ConfigNodeConfig.java    |  71 +++++---------
 .../confignode/conf/ConfigNodeDescriptor.java      |  38 ++++----
 .../confignode/conf/ConfigNodeStartupCheck.java    |   9 +-
 ...eption.java => DatabaseNotExistsException.java} |   6 +-
 .../confignode/manager/ClusterSchemaManager.java   | 105 ++++++++++-----------
 .../iotdb/confignode/manager/ConfigManager.java    |  13 +--
 .../iotdb/confignode/manager/load/LoadManager.java |   6 +-
 .../manager/load/balancer/RegionBalancer.java      |   6 +-
 .../manager/partition/PartitionManager.java        |  62 ++++++------
 .../persistence/executor/ConfigPlanExecutor.java   |   2 +-
 .../persistence/partition/PartitionInfo.java       |   8 +-
 .../persistence/schema/ClusterSchemaInfo.java      |  50 +++++++---
 .../procedure/env/ConfigNodeProcedureEnv.java      |  11 +--
 .../statemachine/CreateRegionGroupsProcedure.java  |   4 +-
 .../thrift/ConfigNodeRPCServiceProcessor.java      |  28 ++++--
 .../persistence/ClusterSchemaInfoTest.java         |   3 +-
 .../resources/conf/iotdb-common.properties         |  44 +++++----
 .../db/mpp/common/header/ColumnHeaderConstant.java |   1 -
 .../config/metadata/SetStorageGroupTask.java       |   7 ++
 .../config/metadata/ShowVariablesTask.java         |   4 -
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |   8 +-
 .../metadata/SetStorageGroupStatement.java         |  72 +++++++++-----
 .../src/main/thrift/confignode.thrift              |  13 +--
 25 files changed, 304 insertions(+), 277 deletions(-)

diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 0d6a2cc46f..6df0533513 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -83,7 +83,7 @@ storageGroupAttributesClause
     ;
 
 storageGroupAttributeClause
-    : (TTL | SCHEMA_REPLICATION_FACTOR | DATA_REPLICATION_FACTOR | TIME_PARTITION_INTERVAL) '=' INTEGER_LITERAL
+    : (TTL | SCHEMA_REPLICATION_FACTOR | DATA_REPLICATION_FACTOR | TIME_PARTITION_INTERVAL | SCHEMA_REGION_GROUP_NUM | DATA_REGION_GROUP_NUM) '=' INTEGER_LITERAL
     ;
 
 // Create Timeseries
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index a407eaf5f4..e30801000d 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -892,6 +892,14 @@ TIME_PARTITION_INTERVAL
     : T I M E '_' P A R T I T I O N '_' I N T E R V A L
     ;
 
+SCHEMA_REGION_GROUP_NUM
+    : S C H E M A '_' R E G I O N '_' G R O U P '_' N U M
+    ;
+
+DATA_REGION_GROUP_NUM
+    : D A T A '_' R E G I O N '_' G R O U P '_' N U M
+    ;
+
 APPLY_TEMPLATE
     : A P P L Y '_' T E M P L A T E
     ;
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
index 55ff24d54d..4056865e9e 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java
@@ -75,35 +75,34 @@ public class ConfigNodeConfig {
   private String seriesPartitionExecutorClass =
       "org.apache.iotdb.commons.partition.executor.hash.BKDRHashExecutor";
 
-  /** The maximum number of SchemaRegions expected to be managed by each DataNode. */
-  private double schemaRegionPerDataNode = schemaReplicationFactor;
-
   /** The policy of extension SchemaRegionGroup for each Database. */
   private RegionGroupExtensionPolicy schemaRegionGroupExtensionPolicy =
       RegionGroupExtensionPolicy.AUTO;
 
-  /** The number of SchemaRegionGroups for each Database when using CUSTOM extension policy */
-  private int schemaRegionGroupPerDatabase = 1;
+  /**
+   * When set schema_region_group_extension_policy=CUSTOM, this parameter is the default number of
+   * SchemaRegionGroups for each Database. When set schema_region_group_extension_policy=AUTO, this
+   * parameter is the default minimal number of SchemaRegionGroups for each Database.
+   */
+  private int defaultSchemaRegionGroupPerDatabase = 1;
+
+  /** The maximum number of SchemaRegions expected to be managed by each DataNode. */
+  private double schemaRegionPerDataNode = schemaReplicationFactor;
 
   /** The policy of extension DataRegionGroup for each Database. */
   private RegionGroupExtensionPolicy dataRegionGroupExtensionPolicy =
       RegionGroupExtensionPolicy.AUTO;
 
-  /** The number of DataRegionGroups for each Database when using CUSTOM extension policy */
-  private int dataRegionGroupPerDatabase = 1;
+  /**
+   * When set data_region_group_extension_policy=CUSTOM, this parameter is the default number of
+   * DataRegionGroups for each Database. When set data_region_group_extension_policy=AUTO, this
+   * parameter is the default minimal number of DataRegionGroups for each Database.
+   */
+  private int defaultDataRegionGroupPerDatabase = 1;
 
   /** The maximum number of DataRegions expected to be managed by each DataNode. */
   private double dataRegionPerProcessor = 1.0;
 
-  /** The least number of SchemaRegionGroup for each Database. */
-  private volatile int leastSchemaRegionGroupNum = 1;
-
-  /** The least number of DataRegionGroup for each Database. */
-  private volatile int leastDataRegionGroupNum = 5;
-
-  /** Indicate whether the leastDataRegionGroupNum is set by user, if true, lock it. */
-  private volatile boolean leastDataRegionGroupNumSetByUser = false;
-
   /** RegionGroup allocate policy. */
   private RegionBalancer.RegionGroupAllocatePolicy regionGroupAllocatePolicy =
       RegionBalancer.RegionGroupAllocatePolicy.GREEDY;
@@ -478,12 +477,12 @@ public class ConfigNodeConfig {
     this.schemaRegionGroupExtensionPolicy = schemaRegionGroupExtensionPolicy;
   }
 
-  public int getSchemaRegionGroupPerDatabase() {
-    return schemaRegionGroupPerDatabase;
+  public int getDefaultSchemaRegionGroupPerDatabase() {
+    return defaultSchemaRegionGroupPerDatabase;
   }
 
-  public void setSchemaRegionGroupPerDatabase(int schemaRegionGroupPerDatabase) {
-    this.schemaRegionGroupPerDatabase = schemaRegionGroupPerDatabase;
+  public void setDefaultSchemaRegionGroupPerDatabase(int defaultSchemaRegionGroupPerDatabase) {
+    this.defaultSchemaRegionGroupPerDatabase = defaultSchemaRegionGroupPerDatabase;
   }
 
   public RegionGroupExtensionPolicy getDataRegionGroupExtensionPolicy() {
@@ -495,12 +494,12 @@ public class ConfigNodeConfig {
     this.dataRegionGroupExtensionPolicy = dataRegionGroupExtensionPolicy;
   }
 
-  public int getDataRegionGroupPerDatabase() {
-    return dataRegionGroupPerDatabase;
+  public int getDefaultDataRegionGroupPerDatabase() {
+    return defaultDataRegionGroupPerDatabase;
   }
 
-  public void setDataRegionGroupPerDatabase(int dataRegionGroupPerDatabase) {
-    this.dataRegionGroupPerDatabase = dataRegionGroupPerDatabase;
+  public void setDefaultDataRegionGroupPerDatabase(int defaultDataRegionGroupPerDatabase) {
+    this.defaultDataRegionGroupPerDatabase = defaultDataRegionGroupPerDatabase;
   }
 
   public double getSchemaRegionPerDataNode() {
@@ -527,30 +526,6 @@ public class ConfigNodeConfig {
     this.dataRegionPerProcessor = dataRegionPerProcessor;
   }
 
-  public int getLeastSchemaRegionGroupNum() {
-    return leastSchemaRegionGroupNum;
-  }
-
-  public void setLeastSchemaRegionGroupNum(int leastSchemaRegionGroupNum) {
-    this.leastSchemaRegionGroupNum = leastSchemaRegionGroupNum;
-  }
-
-  public int getLeastDataRegionGroupNum() {
-    return leastDataRegionGroupNum;
-  }
-
-  public void setLeastDataRegionGroupNum(int leastDataRegionGroupNum) {
-    this.leastDataRegionGroupNum = leastDataRegionGroupNum;
-  }
-
-  public boolean isLeastDataRegionGroupNumSetByUser() {
-    return leastDataRegionGroupNumSetByUser;
-  }
-
-  public void setLeastDataRegionGroupNumSetByUser(boolean leastDataRegionGroupNumSetByUser) {
-    this.leastDataRegionGroupNumSetByUser = leastDataRegionGroupNumSetByUser;
-  }
-
   public RegionBalancer.RegionGroupAllocatePolicy getRegionGroupAllocatePolicy() {
     return regionGroupAllocatePolicy;
   }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
index 787bc84cbc..2e0900a9fd 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
@@ -215,25 +215,27 @@ public class ConfigNodeDescriptor {
                     "data_replication_factor", String.valueOf(conf.getDataReplicationFactor()))
                 .trim()));
 
-    conf.setSchemaRegionPerDataNode(
-        Double.parseDouble(
-            properties
-                .getProperty(
-                    "schema_region_per_data_node",
-                    String.valueOf(conf.getSchemaReplicationFactor()))
-                .trim()));
-
     conf.setSchemaRegionGroupExtensionPolicy(
         RegionGroupExtensionPolicy.parse(
             properties.getProperty(
                 "schema_region_group_extension_policy",
                 conf.getSchemaRegionGroupExtensionPolicy().getPolicy().trim())));
 
-    conf.setSchemaRegionGroupPerDatabase(
+    conf.setDefaultSchemaRegionGroupPerDatabase(
         Integer.parseInt(
-            properties.getProperty(
-                "schema_region_group_per_database",
-                String.valueOf(conf.getSchemaRegionGroupPerDatabase()).trim())));
+            properties
+                .getProperty(
+                    "default_schema_region_group_per_database",
+                    String.valueOf(conf.getDefaultSchemaRegionGroupPerDatabase()))
+                .trim()));
+
+    conf.setSchemaRegionPerDataNode(
+        Double.parseDouble(
+            properties
+                .getProperty(
+                    "schema_region_per_data_node",
+                    String.valueOf(conf.getSchemaReplicationFactor()))
+                .trim()));
 
     conf.setDataRegionGroupExtensionPolicy(
         RegionGroupExtensionPolicy.parse(
@@ -241,11 +243,11 @@ public class ConfigNodeDescriptor {
                 "data_region_group_extension_policy",
                 conf.getDataRegionGroupExtensionPolicy().getPolicy().trim())));
 
-    conf.setDataRegionGroupPerDatabase(
+    conf.setDefaultDataRegionGroupPerDatabase(
         Integer.parseInt(
             properties.getProperty(
-                "data_region_group_per_database",
-                String.valueOf(conf.getDataRegionGroupPerDatabase()).trim())));
+                "default_data_region_group_per_database",
+                String.valueOf(conf.getDefaultDataRegionGroupPerDatabase()).trim())));
 
     conf.setDataRegionPerProcessor(
         Double.parseDouble(
@@ -254,12 +256,6 @@ public class ConfigNodeDescriptor {
                     "data_region_per_processor", String.valueOf(conf.getDataRegionPerProcessor()))
                 .trim()));
 
-    if (properties.getProperty("least_data_region_group_num") != null) {
-      conf.setLeastDataRegionGroupNum(
-          Integer.parseInt(properties.getProperty("least_data_region_group_num")));
-      conf.setLeastDataRegionGroupNumSetByUser(true);
-    }
-
     try {
       conf.setRegionAllocateStrategy(
           RegionBalancer.RegionGroupAllocatePolicy.valueOf(
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java
index b70e20bb9c..02c1304d77 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java
@@ -112,9 +112,12 @@ public class ConfigNodeStartupCheck {
           "The ip address of any target_config_node_list couldn't be 0.0.0.0");
     }
 
-    // The least DataRegionGroup number should be positive
-    if (CONF.getLeastDataRegionGroupNum() <= 0) {
-      throw new ConfigurationException("The least_data_region_group_num should be positive");
+    // The least RegionGroupNum should be positive
+    if (CONF.getDefaultSchemaRegionGroupPerDatabase() <= 0) {
+      throw new ConfigurationException("The default_schema_region_group_num should be positive");
+    }
+    if (CONF.getDefaultDataRegionGroupPerDatabase() <= 0) {
+      throw new ConfigurationException("The default_data_region_group_num should be positive");
     }
   }
 
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/exception/StorageGroupNotExistsException.java b/confignode/src/main/java/org/apache/iotdb/confignode/exception/DatabaseNotExistsException.java
similarity index 80%
rename from confignode/src/main/java/org/apache/iotdb/confignode/exception/StorageGroupNotExistsException.java
rename to confignode/src/main/java/org/apache/iotdb/confignode/exception/DatabaseNotExistsException.java
index aa1a198496..38ac9a8ee0 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/exception/StorageGroupNotExistsException.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/exception/DatabaseNotExistsException.java
@@ -18,9 +18,9 @@
  */
 package org.apache.iotdb.confignode.exception;
 
-public class StorageGroupNotExistsException extends ConfigNodeException {
+public class DatabaseNotExistsException extends ConfigNodeException {
 
-  public StorageGroupNotExistsException(String storageGroup) {
-    super(String.format("StorageGroup: %s doesn't exist.", storageGroup));
+  public DatabaseNotExistsException(String database) {
+    super(String.format("Database: %s doesn't exist.", database));
   }
 }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterSchemaManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterSchemaManager.java
index 7e6a7e57e0..c50c4924af 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterSchemaManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterSchemaManager.java
@@ -59,7 +59,7 @@ import org.apache.iotdb.confignode.consensus.response.PathInfoResp;
 import org.apache.iotdb.confignode.consensus.response.StorageGroupSchemaResp;
 import org.apache.iotdb.confignode.consensus.response.TemplateInfoResp;
 import org.apache.iotdb.confignode.consensus.response.TemplateSetInfoResp;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.manager.node.NodeManager;
 import org.apache.iotdb.confignode.manager.observer.NodeStatisticsEvent;
 import org.apache.iotdb.confignode.manager.partition.PartitionManager;
@@ -207,7 +207,7 @@ public class ClusterSchemaManager {
             getPartitionManager().getRegionGroupCount(name, TConsensusGroupType.SchemaRegion));
         storageGroupInfo.setDataRegionNum(
             getPartitionManager().getRegionGroupCount(name, TConsensusGroupType.DataRegion));
-      } catch (StorageGroupNotExistsException e) {
+      } catch (DatabaseNotExistsException e) {
         // Return immediately if some StorageGroups doesn't exist
         return new TShowStorageGroupResp()
             .setStatus(
@@ -316,7 +316,7 @@ public class ClusterSchemaManager {
   public synchronized void adjustMaxRegionGroupNum() {
     // Get all StorageGroupSchemas
     Map<String, TStorageGroupSchema> storageGroupSchemaMap =
-        getMatchedStorageGroupSchemasByName(getStorageGroupNames());
+        getMatchedDatabaseSchemasByName(getDatabaseNames());
     if (storageGroupSchemaMap.size() == 0) {
       // Skip when there are no StorageGroups
       return;
@@ -326,25 +326,6 @@ public class ClusterSchemaManager {
     int totalCpuCoreNum = getNodeManager().getTotalCpuCoreCount();
     int storageGroupNum = storageGroupSchemaMap.size();
 
-    // Adjust least_data_region_group_num
-    // TODO: The least_data_region_group_num should be maintained separately by different
-    // TODO: StorageGroup
-    if (!CONF.isLeastDataRegionGroupNumSetByUser()) {
-      int leastDataRegionGroupNum =
-          (int)
-              Math.ceil(
-                  (double) totalCpuCoreNum
-                      / (double) (storageGroupNum * CONF.getDataReplicationFactor()));
-      if (leastDataRegionGroupNum < CONF.getLeastDataRegionGroupNum()) {
-        // The leastDataRegionGroupNum should be the maximum integer that satisfy:
-        // 1 <= leastDataRegionGroupNum <= 5(default)
-        CONF.setLeastDataRegionGroupNum(leastDataRegionGroupNum);
-        LOGGER.info(
-            "[AdjustRegionGroupNum] The least number of DataRegionGroups per Database is adjusted to: {}",
-            leastDataRegionGroupNum);
-      }
-    }
-
     AdjustMaxRegionGroupNumPlan adjustMaxRegionGroupNumPlan = new AdjustMaxRegionGroupNumPlan();
     for (TStorageGroupSchema storageGroupSchema : storageGroupSchemaMap.values()) {
       try {
@@ -357,7 +338,7 @@ public class ClusterSchemaManager {
                     storageGroupSchema.getName(), TConsensusGroupType.SchemaRegion);
         int maxSchemaRegionGroupNum =
             calcMaxRegionGroupNum(
-                CONF.getLeastSchemaRegionGroupNum(),
+                storageGroupSchema.getMinSchemaRegionGroupNum(),
                 SCHEMA_REGION_PER_DATA_NODE,
                 dataNodeNum,
                 storageGroupNum,
@@ -376,7 +357,7 @@ public class ClusterSchemaManager {
                 .getRegionGroupCount(storageGroupSchema.getName(), TConsensusGroupType.DataRegion);
         int maxDataRegionGroupNum =
             calcMaxRegionGroupNum(
-                CONF.getLeastDataRegionGroupNum(),
+                storageGroupSchema.getMinDataRegionGroupNum(),
                 DATA_REGION_PER_PROCESSOR,
                 totalCpuCoreNum,
                 storageGroupNum,
@@ -390,7 +371,7 @@ public class ClusterSchemaManager {
         adjustMaxRegionGroupNumPlan.putEntry(
             storageGroupSchema.getName(),
             new Pair<>(maxSchemaRegionGroupNum, maxDataRegionGroupNum));
-      } catch (StorageGroupNotExistsException e) {
+      } catch (DatabaseNotExistsException e) {
         LOGGER.warn("Adjust maxRegionGroupNum failed because StorageGroup doesn't exist", e);
       }
     }
@@ -424,63 +405,73 @@ public class ClusterSchemaManager {
   // ======================================================
 
   /**
-   * Only leader use this interface.
+   * Only leader use this interface. Get all Databases name
    *
-   * @param storageGroup StorageGroupName
-   * @return The specific StorageGroupSchema
-   * @throws StorageGroupNotExistsException When the specific StorageGroup doesn't exist
+   * @return List<DatabaseName>, all Databases' name
    */
-  public TStorageGroupSchema getStorageGroupSchemaByName(String storageGroup)
-      throws StorageGroupNotExistsException {
-    return clusterSchemaInfo.getMatchedStorageGroupSchemaByName(storageGroup);
+  public List<String> getDatabaseNames() {
+    return clusterSchemaInfo.getDatabaseNames();
   }
 
   /**
-   * Only leader use this interface
+   * Only leader use this interface. Get the specified Database's schema
    *
-   * @param storageGroup StorageGroupName
-   * @param consensusGroupType SchemaRegion for SchemaReplicationFactor and DataRegion for
-   *     DataReplicationFactor
-   * @return SchemaReplicationFactor or DataReplicationFactor
-   * @throws StorageGroupNotExistsException When the specific StorageGroup doesn't exist
+   * @param database DatabaseName
+   * @return The specific DatabaseSchema
+   * @throws DatabaseNotExistsException When the specific Database doesn't exist
    */
-  public int getReplicationFactor(String storageGroup, TConsensusGroupType consensusGroupType)
-      throws StorageGroupNotExistsException {
-    TStorageGroupSchema storageGroupSchema = getStorageGroupSchemaByName(storageGroup);
-    return consensusGroupType == TConsensusGroupType.SchemaRegion
-        ? storageGroupSchema.getSchemaReplicationFactor()
-        : storageGroupSchema.getDataReplicationFactor();
+  public TStorageGroupSchema getDatabaseSchemaByName(String database)
+      throws DatabaseNotExistsException {
+    return clusterSchemaInfo.getMatchedDatabaseSchemaByName(database);
   }
 
   /**
-   * Only leader use this interface.
+   * Only leader use this interface. Get the specified Databases' schema
    *
-   * @param rawPathList List<StorageGroupName>
-   * @return the matched StorageGroupSchemas
+   * @param rawPathList List<DatabaseName>
+   * @return the matched DatabaseSchemas
    */
-  public Map<String, TStorageGroupSchema> getMatchedStorageGroupSchemasByName(
+  public Map<String, TStorageGroupSchema> getMatchedDatabaseSchemasByName(
       List<String> rawPathList) {
-    return clusterSchemaInfo.getMatchedStorageGroupSchemasByName(rawPathList);
+    return clusterSchemaInfo.getMatchedDatabaseSchemasByName(rawPathList);
   }
 
   /**
-   * Only leader use this interface.
+   * Only leader use this interface. Get the replication factor of specified Database
    *
-   * @return List<StorageGroupName>, all StorageGroups' name
+   * @param database DatabaseName
+   * @param consensusGroupType SchemaRegion or DataRegion
+   * @return SchemaReplicationFactor or DataReplicationFactor
+   * @throws DatabaseNotExistsException When the specific StorageGroup doesn't exist
+   */
+  public int getReplicationFactor(String database, TConsensusGroupType consensusGroupType)
+      throws DatabaseNotExistsException {
+    TStorageGroupSchema storageGroupSchema = getDatabaseSchemaByName(database);
+    return TConsensusGroupType.SchemaRegion.equals(consensusGroupType)
+        ? storageGroupSchema.getSchemaReplicationFactor()
+        : storageGroupSchema.getDataReplicationFactor();
+  }
+
+  /**
+   * Only leader use this interface. Get the maxRegionGroupNum of specified Database.
+   *
+   * @param database DatabaseName
+   * @param consensusGroupType SchemaRegion or DataRegion
+   * @return minSchemaRegionGroupNum or minDataRegionGroupNum
    */
-  public List<String> getStorageGroupNames() {
-    return clusterSchemaInfo.getStorageGroupNames();
+  public int getMinRegionGroupNum(String database, TConsensusGroupType consensusGroupType) {
+    return clusterSchemaInfo.getMinRegionGroupNum(database, consensusGroupType);
   }
 
   /**
-   * Only leader use this interface. Get the maxRegionGroupNum of specific StorageGroup.
+   * Only leader use this interface. Get the maxRegionGroupNum of specified Database.
    *
-   * @param storageGroup StorageGroupName
+   * @param database DatabaseName
    * @param consensusGroupType SchemaRegion or DataRegion
    * @return maxSchemaRegionGroupNum or maxDataRegionGroupNum
    */
-  public int getMaxRegionGroupNum(String storageGroup, TConsensusGroupType consensusGroupType) {
-    return clusterSchemaInfo.getMaxRegionGroupNum(storageGroup, consensusGroupType);
+  public int getMaxRegionGroupNum(String database, TConsensusGroupType consensusGroupType) {
+    return clusterSchemaInfo.getMaxRegionGroupNum(database, consensusGroupType);
   }
 
   /**
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index 47ece8115c..36371078e8 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -439,7 +439,6 @@ public class ConfigManager implements IManager {
     clusterParameters.setSchemaRegionPerDataNode(CONF.getSchemaRegionPerDataNode());
     clusterParameters.setDiskSpaceWarningThreshold(COMMON_CONF.getDiskSpaceWarningThreshold());
     clusterParameters.setReadConsistencyLevel(CONF.getReadConsistencyLevel());
-    clusterParameters.setLeastDataRegionGroupNum(CONF.getLeastDataRegionGroupNum());
     return clusterParameters;
   }
 
@@ -526,7 +525,7 @@ public class ConfigManager implements IManager {
     if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
       // remove wild
       Map<String, TStorageGroupSchema> deleteStorageSchemaMap =
-          getClusterSchemaManager().getMatchedStorageGroupSchemasByName(deletedPaths);
+          getClusterSchemaManager().getMatchedDatabaseSchemasByName(deletedPaths);
       if (deleteStorageSchemaMap.isEmpty()) {
         return RpcUtils.getStatus(
             TSStatusCode.PATH_NOT_EXIST.getStatusCode(),
@@ -569,7 +568,7 @@ public class ConfigManager implements IManager {
     // Build GetSchemaPartitionPlan
     Map<String, Set<TSeriesPartitionSlot>> partitionSlotsMap = new HashMap<>();
     List<PartialPath> relatedPaths = patternTree.getAllPathPatterns();
-    List<String> allStorageGroups = getClusterSchemaManager().getStorageGroupNames();
+    List<String> allStorageGroups = getClusterSchemaManager().getDatabaseNames();
     List<PartialPath> allStorageGroupPaths = new ArrayList<>();
     for (String storageGroup : allStorageGroups) {
       try {
@@ -627,7 +626,7 @@ public class ConfigManager implements IManager {
     }
 
     List<String> devicePaths = patternTree.getAllDevicePatterns();
-    List<String> storageGroups = getClusterSchemaManager().getStorageGroupNames();
+    List<String> storageGroups = getClusterSchemaManager().getDatabaseNames();
 
     // Build GetOrCreateSchemaPartitionPlan
     Map<String, List<TSeriesPartitionSlot>> partitionSlotsMap = new HashMap<>();
@@ -936,10 +935,6 @@ public class ConfigManager implements IManager {
       return errorStatus.setMessage(errorPrefix + "disk_space_warning_threshold" + errorSuffix);
     }
 
-    if (clusterParameters.getLeastDataRegionGroupNum() != CONF.getLeastDataRegionGroupNum()) {
-      return errorStatus.setMessage(errorPrefix + "least_data_region_group_num" + errorSuffix);
-    }
-
     return null;
   }
 
@@ -1216,7 +1211,7 @@ public class ConfigManager implements IManager {
       return noExistSg;
     }
     for (PartialPath storageGroup : storageGroups) {
-      if (!clusterSchemaManager.getStorageGroupNames().contains(storageGroup.toString())) {
+      if (!clusterSchemaManager.getDatabaseNames().contains(storageGroup.toString())) {
         noExistSg.add(storageGroup);
       }
     }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/LoadManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/LoadManager.java
index b23d2fa11f..33d9ed4398 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/LoadManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/LoadManager.java
@@ -36,9 +36,9 @@ import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler;
 import org.apache.iotdb.confignode.conf.ConfigNodeConfig;
 import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
 import org.apache.iotdb.confignode.consensus.request.write.region.CreateRegionGroupsPlan;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.exception.NoAvailableRegionGroupException;
 import org.apache.iotdb.confignode.exception.NotEnoughDataNodeException;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
 import org.apache.iotdb.confignode.manager.ClusterSchemaManager;
 import org.apache.iotdb.confignode.manager.ConsensusManager;
 import org.apache.iotdb.confignode.manager.IManager;
@@ -119,11 +119,11 @@ public class LoadManager {
    * @param consensusGroupType TConsensusGroupType of RegionGroup to be allocated
    * @return CreateRegionGroupsPlan
    * @throws NotEnoughDataNodeException If there are not enough DataNodes
-   * @throws StorageGroupNotExistsException If some specific StorageGroups don't exist
+   * @throws DatabaseNotExistsException If some specific StorageGroups don't exist
    */
   public CreateRegionGroupsPlan allocateRegionGroups(
       Map<String, Integer> allotmentMap, TConsensusGroupType consensusGroupType)
-      throws NotEnoughDataNodeException, StorageGroupNotExistsException {
+      throws NotEnoughDataNodeException, DatabaseNotExistsException {
     return regionBalancer.genRegionGroupsAllocationPlan(allotmentMap, consensusGroupType);
   }
 
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RegionBalancer.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RegionBalancer.java
index 7b95777536..2a33f6bcd7 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RegionBalancer.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RegionBalancer.java
@@ -25,8 +25,8 @@ import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet;
 import org.apache.iotdb.commons.cluster.NodeStatus;
 import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
 import org.apache.iotdb.confignode.consensus.request.write.region.CreateRegionGroupsPlan;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.exception.NotEnoughDataNodeException;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
 import org.apache.iotdb.confignode.manager.ClusterSchemaManager;
 import org.apache.iotdb.confignode.manager.IManager;
 import org.apache.iotdb.confignode.manager.load.balancer.region.CopySetRegionGroupAllocator;
@@ -67,11 +67,11 @@ public class RegionBalancer {
    * @param consensusGroupType TConsensusGroupType of the new RegionGroups
    * @return CreateRegionGroupsPlan
    * @throws NotEnoughDataNodeException When the number of DataNodes is not enough for allocation
-   * @throws StorageGroupNotExistsException When some StorageGroups don't exist
+   * @throws DatabaseNotExistsException When some StorageGroups don't exist
    */
   public CreateRegionGroupsPlan genRegionGroupsAllocationPlan(
       Map<String, Integer> allotmentMap, TConsensusGroupType consensusGroupType)
-      throws NotEnoughDataNodeException, StorageGroupNotExistsException {
+      throws NotEnoughDataNodeException, DatabaseNotExistsException {
 
     // The new RegionGroups will occupy online DataNodes firstly
     List<TDataNodeConfiguration> onlineDataNodes =
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java
index fafb478be7..588b9c99f2 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java
@@ -59,9 +59,9 @@ import org.apache.iotdb.confignode.consensus.response.GetTimeSlotListResp;
 import org.apache.iotdb.confignode.consensus.response.RegionInfoListResp;
 import org.apache.iotdb.confignode.consensus.response.SchemaNodeManagementResp;
 import org.apache.iotdb.confignode.consensus.response.SchemaPartitionResp;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.exception.NoAvailableRegionGroupException;
 import org.apache.iotdb.confignode.exception.NotEnoughDataNodeException;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
 import org.apache.iotdb.confignode.manager.ClusterSchemaManager;
 import org.apache.iotdb.confignode.manager.ConsensusManager;
 import org.apache.iotdb.confignode.manager.IManager;
@@ -107,11 +107,8 @@ public class PartitionManager {
   private static final ConfigNodeConfig CONF = ConfigNodeDescriptor.getInstance().getConf();
   private static final RegionGroupExtensionPolicy SCHEMA_REGION_GROUP_EXTENSION_POLICY =
       CONF.getSchemaRegionGroupExtensionPolicy();
-  private static final int SCHEMA_REGION_GROUP_PER_DATABASE =
-      CONF.getSchemaRegionGroupPerDatabase();
   private static final RegionGroupExtensionPolicy DATA_REGION_GROUP_EXTENSION_POLICY =
       CONF.getDataRegionGroupExtensionPolicy();
-  private static final int DATA_REGION_GROUP_PER_DATABASE = CONF.getDataRegionGroupPerDatabase();
 
   private final IManager configManager;
   private final PartitionInfo partitionInfo;
@@ -366,7 +363,7 @@ public class PartitionManager {
       LOGGER.error(prompt);
       result.setCode(TSStatusCode.NO_ENOUGH_DATANODE.getStatusCode());
       result.setMessage(prompt);
-    } catch (StorageGroupNotExistsException e) {
+    } catch (DatabaseNotExistsException e) {
       String prompt = "ConfigNode failed to extend Region because some StorageGroup doesn't exist.";
       LOGGER.error(prompt);
       result.setCode(TSStatusCode.DATABASE_NOT_EXIST.getStatusCode());
@@ -378,22 +375,21 @@ public class PartitionManager {
 
   private TSStatus customExtendRegionGroupIfNecessary(
       Map<String, Integer> unassignedPartitionSlotsCountMap, TConsensusGroupType consensusGroupType)
-      throws StorageGroupNotExistsException, NotEnoughDataNodeException {
+      throws DatabaseNotExistsException, NotEnoughDataNodeException {
 
     // Map<StorageGroup, Region allotment>
     Map<String, Integer> allotmentMap = new ConcurrentHashMap<>();
 
     for (Map.Entry<String, Integer> entry : unassignedPartitionSlotsCountMap.entrySet()) {
-      final String storageGroup = entry.getKey();
-      float allocatedRegionGroupCount =
-          partitionInfo.getRegionGroupCount(storageGroup, consensusGroupType);
-
-      if (allocatedRegionGroupCount == 0) {
-        allotmentMap.put(
-            storageGroup,
-            TConsensusGroupType.SchemaRegion.equals(consensusGroupType)
-                ? SCHEMA_REGION_GROUP_PER_DATABASE
-                : DATA_REGION_GROUP_PER_DATABASE);
+      final String database = entry.getKey();
+      int minRegionGroupNum =
+          getClusterSchemaManager().getMinRegionGroupNum(database, consensusGroupType);
+      int allocatedRegionGroupCount =
+          partitionInfo.getRegionGroupCount(database, consensusGroupType);
+
+      // Extend RegionGroups until allocatedRegionGroupCount == minRegionGroupNum
+      if (allocatedRegionGroupCount < minRegionGroupNum) {
+        allotmentMap.put(database, minRegionGroupNum - allocatedRegionGroupCount);
       }
     }
 
@@ -402,39 +398,37 @@ public class PartitionManager {
 
   private TSStatus autoExtendRegionGroupIfNecessary(
       Map<String, Integer> unassignedPartitionSlotsCountMap, TConsensusGroupType consensusGroupType)
-      throws NotEnoughDataNodeException, StorageGroupNotExistsException {
+      throws NotEnoughDataNodeException, DatabaseNotExistsException {
 
     // Map<StorageGroup, Region allotment>
     Map<String, Integer> allotmentMap = new ConcurrentHashMap<>();
 
     for (Map.Entry<String, Integer> entry : unassignedPartitionSlotsCountMap.entrySet()) {
-      final String storageGroup = entry.getKey();
+      final String database = entry.getKey();
       final int unassignedPartitionSlotsCount = entry.getValue();
 
       float allocatedRegionGroupCount =
-          partitionInfo.getRegionGroupCount(storageGroup, consensusGroupType);
+          partitionInfo.getRegionGroupCount(database, consensusGroupType);
       // The slotCount equals to the sum of assigned slot count and unassigned slot count
       float slotCount =
-          (float) partitionInfo.getAssignedSeriesPartitionSlotsCount(storageGroup)
+          (float) partitionInfo.getAssignedSeriesPartitionSlotsCount(database)
               + unassignedPartitionSlotsCount;
       float maxRegionGroupCount =
-          getClusterSchemaManager().getMaxRegionGroupNum(storageGroup, consensusGroupType);
+          getClusterSchemaManager().getMaxRegionGroupNum(database, consensusGroupType);
       float maxSlotCount = CONF.getSeriesSlotNum();
 
       /* RegionGroup extension is required in the following cases */
       // 1. The number of current RegionGroup of the StorageGroup is less than the least number
-      int leastRegionGroupNum =
-          TConsensusGroupType.SchemaRegion.equals(consensusGroupType)
-              ? CONF.getLeastSchemaRegionGroupNum()
-              : CONF.getLeastDataRegionGroupNum();
-      if (allocatedRegionGroupCount < leastRegionGroupNum) {
+      int minRegionGroupNum =
+          getClusterSchemaManager().getMinRegionGroupNum(database, consensusGroupType);
+      if (allocatedRegionGroupCount < minRegionGroupNum) {
         // Let the sum of unassignedPartitionSlotsCount and allocatedRegionGroupCount
         // no less than the leastRegionGroupNum
         int delta =
             (int)
                 Math.min(
-                    unassignedPartitionSlotsCount, leastRegionGroupNum - allocatedRegionGroupCount);
-        allotmentMap.put(storageGroup, delta);
+                    unassignedPartitionSlotsCount, minRegionGroupNum - allocatedRegionGroupCount);
+        allotmentMap.put(database, delta);
         continue;
       }
 
@@ -453,15 +447,15 @@ public class PartitionManager {
                         Math.ceil(
                             slotCount * maxRegionGroupCount / maxSlotCount
                                 - allocatedRegionGroupCount)));
-        allotmentMap.put(storageGroup, delta);
+        allotmentMap.put(database, delta);
         continue;
       }
 
       // 3. All RegionGroups in the specified StorageGroup are disabled currently
       if (allocatedRegionGroupCount
-              == filterRegionGroupThroughStatus(storageGroup, RegionGroupStatus.Disabled).size()
+              == filterRegionGroupThroughStatus(database, RegionGroupStatus.Disabled).size()
           && allocatedRegionGroupCount < maxRegionGroupCount) {
-        allotmentMap.put(storageGroup, 1);
+        allotmentMap.put(database, 1);
       }
     }
 
@@ -470,7 +464,7 @@ public class PartitionManager {
 
   private TSStatus generateAndAllocateRegionGroups(
       Map<String, Integer> allotmentMap, TConsensusGroupType consensusGroupType)
-      throws NotEnoughDataNodeException, StorageGroupNotExistsException {
+      throws NotEnoughDataNodeException, DatabaseNotExistsException {
     if (!allotmentMap.isEmpty()) {
       CreateRegionGroupsPlan createRegionGroupsPlan =
           getLoadManager().allocateRegionGroups(allotmentMap, consensusGroupType);
@@ -562,10 +556,10 @@ public class PartitionManager {
    * @param storageGroup StorageGroupName
    * @param type SchemaRegion or DataRegion
    * @return Number of Regions currently owned by the specific StorageGroup
-   * @throws StorageGroupNotExistsException When the specific StorageGroup doesn't exist
+   * @throws DatabaseNotExistsException When the specific StorageGroup doesn't exist
    */
   public int getRegionGroupCount(String storageGroup, TConsensusGroupType type)
-      throws StorageGroupNotExistsException {
+      throws DatabaseNotExistsException {
     return partitionInfo.getRegionGroupCount(storageGroup, type);
   }
 
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
index 47a44c754d..2919db18c7 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
@@ -489,7 +489,7 @@ public class ConfigPlanExecutor {
     if (showRegionReq != null && showRegionReq.isSetStorageGroups()) {
       final List<String> storageGroups = showRegionReq.getStorageGroups();
       final List<String> matchedStorageGroups =
-          clusterSchemaInfo.getMatchedStorageGroupSchemasByName(storageGroups).values().stream()
+          clusterSchemaInfo.getMatchedDatabaseSchemasByName(storageGroups).values().stream()
               .map(TStorageGroupSchema::getName)
               .collect(Collectors.toList());
       if (!matchedStorageGroups.isEmpty()) {
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java
index b8015707cb..b8f5a51099 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/PartitionInfo.java
@@ -53,7 +53,7 @@ import org.apache.iotdb.confignode.consensus.response.GetTimeSlotListResp;
 import org.apache.iotdb.confignode.consensus.response.RegionInfoListResp;
 import org.apache.iotdb.confignode.consensus.response.SchemaNodeManagementResp;
 import org.apache.iotdb.confignode.consensus.response.SchemaPartitionResp;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.persistence.metric.PartitionInfoMetrics;
 import org.apache.iotdb.confignode.persistence.partition.maintainer.RegionMaintainTask;
 import org.apache.iotdb.confignode.rpc.thrift.TRegionInfo;
@@ -614,12 +614,12 @@ public class PartitionInfo implements SnapshotProcessor {
    * @param storageGroup StorageGroupName
    * @param type SchemaRegion or DataRegion
    * @return Number of Regions currently owned by the specific StorageGroup
-   * @throws StorageGroupNotExistsException When the specific StorageGroup doesn't exist
+   * @throws DatabaseNotExistsException When the specific StorageGroup doesn't exist
    */
   public int getRegionGroupCount(String storageGroup, TConsensusGroupType type)
-      throws StorageGroupNotExistsException {
+      throws DatabaseNotExistsException {
     if (!isStorageGroupExisted(storageGroup)) {
-      throw new StorageGroupNotExistsException(storageGroup);
+      throw new DatabaseNotExistsException(storageGroup);
     }
 
     return storageGroupPartitionTables.get(storageGroup).getRegionGroupCount(type);
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
index 29c1ed7bb8..e697d9a15c 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/ClusterSchemaInfo.java
@@ -52,7 +52,7 @@ import org.apache.iotdb.confignode.consensus.response.PathInfoResp;
 import org.apache.iotdb.confignode.consensus.response.StorageGroupSchemaResp;
 import org.apache.iotdb.confignode.consensus.response.TemplateInfoResp;
 import org.apache.iotdb.confignode.consensus.response.TemplateSetInfoResp;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.rpc.thrift.TStorageGroupSchema;
 import org.apache.iotdb.db.metadata.mtree.ConfigMTree;
 import org.apache.iotdb.db.metadata.template.Template;
@@ -353,7 +353,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor {
    *
    * @return List<StorageGroupName>, all storageGroups' name
    */
-  public List<String> getStorageGroupNames() {
+  public List<String> getDatabaseNames() {
     List<String> storageGroups = new ArrayList<>();
     storageGroupReadWriteLock.readLock().lock();
     try {
@@ -387,17 +387,17 @@ public class ClusterSchemaInfo implements SnapshotProcessor {
    *
    * @param storageGroup StorageGroupName
    * @return The specific StorageGroupSchema
-   * @throws StorageGroupNotExistsException When the specific StorageGroup doesn't exist
+   * @throws DatabaseNotExistsException When the specific StorageGroup doesn't exist
    */
-  public TStorageGroupSchema getMatchedStorageGroupSchemaByName(String storageGroup)
-      throws StorageGroupNotExistsException {
+  public TStorageGroupSchema getMatchedDatabaseSchemaByName(String storageGroup)
+      throws DatabaseNotExistsException {
     storageGroupReadWriteLock.readLock().lock();
     try {
       return mTree
           .getStorageGroupNodeByStorageGroupPath(new PartialPath(storageGroup))
           .getStorageGroupSchema();
     } catch (MetadataException e) {
-      throw new StorageGroupNotExistsException(storageGroup);
+      throw new DatabaseNotExistsException(storageGroup);
     } finally {
       storageGroupReadWriteLock.readLock().unlock();
     }
@@ -409,7 +409,7 @@ public class ClusterSchemaInfo implements SnapshotProcessor {
    * @param rawPathList StorageGroups' path patterns or full paths
    * @return All StorageGroupSchemas that matches to the specific StorageGroup patterns
    */
-  public Map<String, TStorageGroupSchema> getMatchedStorageGroupSchemasByName(
+  public Map<String, TStorageGroupSchema> getMatchedDatabaseSchemasByName(
       List<String> rawPathList) {
     Map<String, TStorageGroupSchema> schemaMap = new HashMap<>();
     storageGroupReadWriteLock.readLock().lock();
@@ -431,16 +431,44 @@ public class ClusterSchemaInfo implements SnapshotProcessor {
   }
 
   /**
-   * Only leader use this interface. Get the maxRegionGroupNum of specific StorageGroup.
+   * Only leader use this interface. Get the maxRegionGroupNum of specified Database.
    *
-   * @param storageGroup StorageGroupName
+   * @param database DatabaseName
+   * @param consensusGroupType SchemaRegion or DataRegion
+   * @return maxSchemaRegionGroupNum or maxDataRegionGroupNum
+   */
+  public int getMinRegionGroupNum(String database, TConsensusGroupType consensusGroupType) {
+    storageGroupReadWriteLock.readLock().lock();
+    try {
+      PartialPath path = new PartialPath(database);
+      TStorageGroupSchema storageGroupSchema =
+          mTree.getStorageGroupNodeByStorageGroupPath(path).getStorageGroupSchema();
+      switch (consensusGroupType) {
+        case SchemaRegion:
+          return storageGroupSchema.getMinSchemaRegionGroupNum();
+        case DataRegion:
+        default:
+          return storageGroupSchema.getMinDataRegionGroupNum();
+      }
+    } catch (MetadataException e) {
+      LOGGER.warn(ERROR_NAME, e);
+      return -1;
+    } finally {
+      storageGroupReadWriteLock.readLock().unlock();
+    }
+  }
+
+  /**
+   * Only leader use this interface. Get the maxRegionGroupNum of specified Database.
+   *
+   * @param database DatabaseName
    * @param consensusGroupType SchemaRegion or DataRegion
    * @return maxSchemaRegionGroupNum or maxDataRegionGroupNum
    */
-  public int getMaxRegionGroupNum(String storageGroup, TConsensusGroupType consensusGroupType) {
+  public int getMaxRegionGroupNum(String database, TConsensusGroupType consensusGroupType) {
     storageGroupReadWriteLock.readLock().lock();
     try {
-      PartialPath path = new PartialPath(storageGroup);
+      PartialPath path = new PartialPath(database);
       TStorageGroupSchema storageGroupSchema =
           mTree.getStorageGroupNodeByStorageGroupPath(path).getStorageGroupSchema();
       switch (consensusGroupType) {
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
index 4ef8c1d401..642c4ac669 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java
@@ -42,7 +42,7 @@ import org.apache.iotdb.confignode.consensus.request.write.storagegroup.DeleteSt
 import org.apache.iotdb.confignode.consensus.request.write.storagegroup.PreDeleteStorageGroupPlan;
 import org.apache.iotdb.confignode.exception.AddConsensusGroupException;
 import org.apache.iotdb.confignode.exception.AddPeerException;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.manager.ClusterSchemaManager;
 import org.apache.iotdb.confignode.manager.ConfigManager;
 import org.apache.iotdb.confignode.manager.ConsensusManager;
@@ -496,9 +496,8 @@ public class ConfigNodeProcedureEnv {
     for (String storageGroup : createRegionGroupsPlan.getRegionGroupMap().keySet()) {
       try {
         ttlMap.put(
-            storageGroup,
-            getClusterSchemaManager().getStorageGroupSchemaByName(storageGroup).getTTL());
-      } catch (StorageGroupNotExistsException e) {
+            storageGroup, getClusterSchemaManager().getDatabaseSchemaByName(storageGroup).getTTL());
+      } catch (DatabaseNotExistsException e) {
         // Notice: This line will never reach since we've checked before
         LOG.error("StorageGroup doesn't exist", e);
       }
@@ -523,8 +522,8 @@ public class ConfigNodeProcedureEnv {
     return req;
   }
 
-  public long getTTL(String storageGroup) throws StorageGroupNotExistsException {
-    return getClusterSchemaManager().getStorageGroupSchemaByName(storageGroup).getTTL();
+  public long getTTL(String storageGroup) throws DatabaseNotExistsException {
+    return getClusterSchemaManager().getDatabaseSchemaByName(storageGroup).getTTL();
   }
 
   public void persistRegionGroup(CreateRegionGroupsPlan createRegionGroupsPlan) {
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/statemachine/CreateRegionGroupsProcedure.java b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/statemachine/CreateRegionGroupsProcedure.java
index 357ac703ed..80f0ab1e8b 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/statemachine/CreateRegionGroupsProcedure.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/statemachine/CreateRegionGroupsProcedure.java
@@ -26,7 +26,7 @@ import org.apache.iotdb.commons.utils.TestOnly;
 import org.apache.iotdb.commons.utils.ThriftCommonsSerDeUtils;
 import org.apache.iotdb.confignode.consensus.request.write.region.CreateRegionGroupsPlan;
 import org.apache.iotdb.confignode.consensus.request.write.region.OfferRegionMaintainTasksPlan;
-import org.apache.iotdb.confignode.exception.StorageGroupNotExistsException;
+import org.apache.iotdb.confignode.exception.DatabaseNotExistsException;
 import org.apache.iotdb.confignode.persistence.partition.maintainer.RegionCreateTask;
 import org.apache.iotdb.confignode.persistence.partition.maintainer.RegionDeleteTask;
 import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
@@ -123,7 +123,7 @@ public class CreateRegionGroupsProcedure
                                             regionReplicaSet.getRegionId().getType())) {
                                           try {
                                             createTask.setTTL(env.getTTL(storageGroup));
-                                          } catch (StorageGroupNotExistsException e) {
+                                          } catch (DatabaseNotExistsException e) {
                                             LOGGER.error("Can't get TTL", e);
                                           }
                                         }
diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
index f3091c0066..87d4d96364 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
 import org.apache.iotdb.commons.utils.StatusUtils;
 import org.apache.iotdb.commons.utils.TestOnly;
+import org.apache.iotdb.confignode.conf.ConfigNodeConfig;
 import org.apache.iotdb.confignode.conf.ConfigNodeConstant;
 import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
 import org.apache.iotdb.confignode.conf.SystemPropertiesUtils;
@@ -171,6 +172,9 @@ public class ConfigNodeRPCServiceProcessor implements IConfigNodeRPCService.Ifac
 
   private static final Logger LOGGER = LoggerFactory.getLogger(ConfigNodeRPCServiceProcessor.class);
 
+  private static final ConfigNodeConfig CONFIG_NODE_CONFIG =
+      ConfigNodeDescriptor.getInstance().getConf();
+
   private final ConfigManager configManager;
 
   public ConfigNodeRPCServiceProcessor(ConfigManager configManager) {
@@ -266,7 +270,7 @@ public class ConfigNodeRPCServiceProcessor implements IConfigNodeRPCService.Ifac
   }
 
   @Override
-  public TShowVariablesResp showVariables() throws TException {
+  public TShowVariablesResp showVariables() {
     return configManager.showVariables();
   }
 
@@ -280,20 +284,26 @@ public class ConfigNodeRPCServiceProcessor implements IConfigNodeRPCService.Ifac
     }
     if (!storageGroupSchema.isSetSchemaReplicationFactor()) {
       storageGroupSchema.setSchemaReplicationFactor(
-          ConfigNodeDescriptor.getInstance().getConf().getSchemaReplicationFactor());
+          CONFIG_NODE_CONFIG.getSchemaReplicationFactor());
     }
     if (!storageGroupSchema.isSetDataReplicationFactor()) {
-      storageGroupSchema.setDataReplicationFactor(
-          ConfigNodeDescriptor.getInstance().getConf().getDataReplicationFactor());
+      storageGroupSchema.setDataReplicationFactor(CONFIG_NODE_CONFIG.getDataReplicationFactor());
     }
     if (!storageGroupSchema.isSetTimePartitionInterval()) {
-      storageGroupSchema.setTimePartitionInterval(
-          ConfigNodeDescriptor.getInstance().getConf().getTimePartitionInterval());
+      storageGroupSchema.setTimePartitionInterval(CONFIG_NODE_CONFIG.getTimePartitionInterval());
+    }
+    if (!storageGroupSchema.isSetMinSchemaRegionGroupNum()) {
+      storageGroupSchema.setMinSchemaRegionGroupNum(
+          CONFIG_NODE_CONFIG.getDefaultSchemaRegionGroupPerDatabase());
+    }
+    if (!storageGroupSchema.isSetMinDataRegionGroupNum()) {
+      storageGroupSchema.setMinDataRegionGroupNum(
+          CONFIG_NODE_CONFIG.getDefaultDataRegionGroupPerDatabase());
     }
 
-    // Initialize the maxSchemaRegionGroupCount and maxDataRegionGroupCount as 0
-    storageGroupSchema.setMaxSchemaRegionGroupNum(0);
-    storageGroupSchema.setMaxDataRegionGroupNum(0);
+    // The maxRegionGroupNum is equal to the minRegionGroupNum when initialize
+    storageGroupSchema.setMaxSchemaRegionGroupNum(storageGroupSchema.getMinSchemaRegionGroupNum());
+    storageGroupSchema.setMaxDataRegionGroupNum(storageGroupSchema.getMinDataRegionGroupNum());
 
     SetStorageGroupPlan setReq = new SetStorageGroupPlan(storageGroupSchema);
     TSStatus resp = configManager.setStorageGroup(setReq);
diff --git a/confignode/src/test/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfoTest.java b/confignode/src/test/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfoTest.java
index 03417a5a23..5d5b4923a3 100644
--- a/confignode/src/test/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfoTest.java
+++ b/confignode/src/test/java/org/apache/iotdb/confignode/persistence/ClusterSchemaInfoTest.java
@@ -97,8 +97,7 @@ public class ClusterSchemaInfoTest {
     clusterSchemaInfo.clear();
     clusterSchemaInfo.processLoadSnapshot(snapshotDir);
 
-    Assert.assertEquals(
-        storageGroupPathList.size(), clusterSchemaInfo.getStorageGroupNames().size());
+    Assert.assertEquals(storageGroupPathList.size(), clusterSchemaInfo.getDatabaseNames().size());
 
     GetStorageGroupPlan getStorageGroupReq =
         new GetStorageGroupPlan(Arrays.asList(PathUtils.splitPathToDetachedNodes("root.**")));
diff --git a/node-commons/src/assembly/resources/conf/iotdb-common.properties b/node-commons/src/assembly/resources/conf/iotdb-common.properties
index 2bfc8386cd..32f985bdaf 100644
--- a/node-commons/src/assembly/resources/conf/iotdb-common.properties
+++ b/node-commons/src/assembly/resources/conf/iotdb-common.properties
@@ -85,13 +85,6 @@ cluster_name=defaultCluster
 # series_partition_executor_class=org.apache.iotdb.commons.partition.executor.hash.BKDRHashExecutor
 
 
-# The maximum number of SchemaRegions expected to be managed by each DataNode.
-# Notice: Since each Database requires at least one SchemaRegionGroup to manage its schema,
-# this parameter doesn't limit the number of SchemaRegions when there are too many Databases.
-# Default is equal to the schema_replication_factor.
-# Datatype: Double
-# schema_region_per_data_node=1.0
-
 # The policy of extension SchemaRegionGroup for each Database.
 # These policies are currently supported:
 # 1. CUSTOM(Each Database will allocate schema_region_group_per_database RegionGroups as soon as created)
@@ -99,10 +92,20 @@ cluster_name=defaultCluster
 # Datatype: String
 # schema_region_group_extension_policy=AUTO
 
-# The number of SchemaRegionGroups for each Database when using CUSTOM schema_region_group_extension_policy.
-# Notice: Each Database will allocate schema_region_group_per_database SchemaRegionGroups as soon as created.
+# When set schema_region_group_extension_policy=CUSTOM,
+# this parameter is the default number of SchemaRegionGroups for each Database.
+# When set schema_region_group_extension_policy=AUTO,
+# this parameter is the default minimal number of SchemaRegionGroups for each Database.
 # Datatype: Integer
-# schema_region_group_per_database=1
+# default_schema_region_group_per_database=1
+
+# Only take effect when set schema_region_group_extension_policy=AUTO.
+# This parameter is the maximum number of SchemaRegions expected to be managed by each DataNode.
+# Notice: Since each Database requires at least one SchemaRegionGroup to manage its schema,
+# this parameter doesn't limit the upper bound of cluster SchemaRegions when there are too many Databases.
+# Default is equal to the schema_replication_factor.
+# Datatype: Double
+# schema_region_per_data_node=
 
 # The policy of extension DataRegionGroup for each Database.
 # These policies are currently supported:
@@ -111,25 +114,20 @@ cluster_name=defaultCluster
 # Datatype: String
 # data_region_group_extension_policy=AUTO
 
-# The number of DataRegionGroups for each Database when using CUSTOM data_region_group_extension_policy.
-# Notice: Each Database will allocate data_region_group_per_database DataRegionGroups as soon as created.
+# When set data_region_group_extension_policy=CUSTOM,
+# this parameter is the default number of DataRegionGroups for each Database.
+# When set data_region_group_extension_policy=AUTO,
+# this parameter is the default minimal number of DataRegionGroups for each Database.
 # Datatype: Integer
-# data_region_group_per_database=1
+# default_data_region_group_per_database=1
 
-# The maximum number of DataRegions expected to be managed by each processor
-# when using AUTO data_region_group_extension_policy.
+# Only take effect when set data_region_group_extension_policy=AUTO.
+# This parameter is the maximum number of DataRegions expected to be managed by each processor.
 # Notice: Since each Database requires at least two DataRegionGroups to manage its data,
-# this parameter doesn't limit the number of DataRegions when there are too many Databases.
+# this parameter doesn't limit the upper bound of cluster DataRegions when there are too many Databases.
 # Datatype: Double
 # data_region_per_processor=1.0
 
-# The least number of DataRegionGroup for each StorageGroup.
-# The ConfigNode-leader will create a DataRegionGroup for each newborn SeriesPartitionSlot
-# for the newly created StorageGroup until the number of DataRegionGroup is equal to this parameter.
-# Notice: In order to ensure the efficiency of concurrent write, this parameter should greater than 1.
-# Datatype: int
-# least_data_region_group_num=5
-
 
 # Whether to enable the DataPartition inherit policy.
 # DataPartition within the same SeriesPartitionSlot will inherit
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/common/header/ColumnHeaderConstant.java b/server/src/main/java/org/apache/iotdb/db/mpp/common/header/ColumnHeaderConstant.java
index ebddd19f06..9fe84ed12a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/common/header/ColumnHeaderConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/common/header/ColumnHeaderConstant.java
@@ -110,7 +110,6 @@ public class ColumnHeaderConstant {
   public static final String DATA_REGION_PER_PROCESSOR = "DataRegionPerProcessor";
   public static final String READ_CONSISTENCY_LEVEL = "ReadConsistencyLevel";
   public static final String DISK_SPACE_WARNING_THRESHOLD = "DiskSpaceWarningThreshold";
-  public static final String LEAST_DATA_REGION_GROUP_NUM = "LeastDataRegionGroupNum";
 
   // column names for show region statement
   public static final String REGION_ID = "RegionId";
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/SetStorageGroupTask.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/SetStorageGroupTask.java
index 5af256ff0f..c5b601a451 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/SetStorageGroupTask.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/SetStorageGroupTask.java
@@ -62,6 +62,13 @@ public class SetStorageGroupTask implements IConfigTask {
       storageGroupSchema.setTimePartitionInterval(
           setStorageGroupStatement.getTimePartitionInterval());
     }
+    if (setStorageGroupStatement.getSchemaRegionGroupNum() != null) {
+      storageGroupSchema.setMinSchemaRegionGroupNum(
+          setStorageGroupStatement.getSchemaRegionGroupNum());
+    }
+    if (setStorageGroupStatement.getDataRegionGroupNum() != null) {
+      storageGroupSchema.setMinDataRegionGroupNum(setStorageGroupStatement.getDataRegionGroupNum());
+    }
     return storageGroupSchema;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowVariablesTask.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowVariablesTask.java
index 794d3aa84c..90e3ffd166 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowVariablesTask.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowVariablesTask.java
@@ -105,10 +105,6 @@ public class ShowVariablesTask implements IConfigTask {
         builder,
         new Binary(ColumnHeaderConstant.DATA_REGION_PER_PROCESSOR),
         new Binary(String.valueOf(clusterParameters.getDataRegionPerProcessor())));
-    buildTSBlock(
-        builder,
-        new Binary(ColumnHeaderConstant.LEAST_DATA_REGION_GROUP_NUM),
-        new Binary(String.valueOf(clusterParameters.getLeastDataRegionGroupNum())));
     buildTSBlock(
         builder,
         new Binary(ColumnHeaderConstant.SERIES_SLOT_NUM),
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 919b943b8b..83f69affcb 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -1933,7 +1933,7 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
         ctx.storageGroupAttributeClause()) {
       if (attribute.TTL() != null) {
         long ttl = Long.parseLong(attribute.INTEGER_LITERAL().getText());
-        setStorageGroupStatement.setTtl(ttl);
+        setStorageGroupStatement.setTTL(ttl);
       } else if (attribute.SCHEMA_REPLICATION_FACTOR() != null) {
         int schemaReplicationFactor = Integer.parseInt(attribute.INTEGER_LITERAL().getText());
         setStorageGroupStatement.setSchemaReplicationFactor(schemaReplicationFactor);
@@ -1943,6 +1943,12 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
       } else if (attribute.TIME_PARTITION_INTERVAL() != null) {
         long timePartitionInterval = Long.parseLong(attribute.INTEGER_LITERAL().getText());
         setStorageGroupStatement.setTimePartitionInterval(timePartitionInterval);
+      } else if (attribute.SCHEMA_REGION_GROUP_NUM() != null) {
+        int schemaRegionGroupNum = Integer.parseInt(attribute.SCHEMA_REGION_GROUP_NUM().getText());
+        setStorageGroupStatement.setSchemaRegionGroupNum(schemaRegionGroupNum);
+      } else if (attribute.DATA_REGION_GROUP_NUM() != null) {
+        int dataRegionGroupNum = Integer.parseInt(attribute.DATA_REGION_GROUP_NUM().getText());
+        setStorageGroupStatement.setDataRegionGroupNum(dataRegionGroupNum);
       }
     }
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/SetStorageGroupStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/SetStorageGroupStatement.java
index 86092522b1..46c55337b5 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/SetStorageGroupStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/SetStorageGroupStatement.java
@@ -31,10 +31,12 @@ import java.util.List;
 
 public class SetStorageGroupStatement extends Statement implements IConfigStatement {
   private PartialPath storageGroupPath;
-  private Long ttl = null;
+  private Long TTL = null;
   private Integer schemaReplicationFactor = null;
   private Integer dataReplicationFactor = null;
   private Long timePartitionInterval = null;
+  private Integer schemaRegionGroupNum = null;
+  private Integer dataRegionGroupNum = null;
 
   public SetStorageGroupStatement() {
     super();
@@ -45,57 +47,73 @@ public class SetStorageGroupStatement extends Statement implements IConfigStatem
     return storageGroupPath;
   }
 
-  @Override
-  public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
-    return visitor.visitSetStorageGroup(this, context);
-  }
-
   public void setStorageGroupPath(PartialPath storageGroupPath) {
     this.storageGroupPath = storageGroupPath;
   }
 
-  public void setTtl(Long ttl) {
-    this.ttl = ttl;
+  public Long getTTL() {
+    return TTL;
+  }
+
+  public void setTTL(Long TTL) {
+    this.TTL = TTL;
+  }
+
+  public Integer getSchemaReplicationFactor() {
+    return schemaReplicationFactor;
   }
 
   public void setSchemaReplicationFactor(Integer schemaReplicationFactor) {
     this.schemaReplicationFactor = schemaReplicationFactor;
   }
 
+  public Integer getDataReplicationFactor() {
+    return dataReplicationFactor;
+  }
+
   public void setDataReplicationFactor(Integer dataReplicationFactor) {
     this.dataReplicationFactor = dataReplicationFactor;
   }
 
+  public Long getTimePartitionInterval() {
+    return timePartitionInterval;
+  }
+
   public void setTimePartitionInterval(Long timePartitionInterval) {
     this.timePartitionInterval = timePartitionInterval;
   }
 
-  @Override
-  public QueryType getQueryType() {
-    return QueryType.WRITE;
+  public Integer getSchemaRegionGroupNum() {
+    return schemaRegionGroupNum;
   }
 
-  @Override
-  public List<PartialPath> getPaths() {
-    return storageGroupPath != null
-        ? Collections.singletonList(storageGroupPath)
-        : Collections.emptyList();
+  public void setSchemaRegionGroupNum(Integer schemaRegionGroupNum) {
+    this.schemaRegionGroupNum = schemaRegionGroupNum;
   }
 
-  public Long getTTL() {
-    return ttl;
+  public Integer getDataRegionGroupNum() {
+    return dataRegionGroupNum;
   }
 
-  public Integer getSchemaReplicationFactor() {
-    return schemaReplicationFactor;
+  public void setDataRegionGroupNum(Integer dataRegionGroupNum) {
+    this.dataRegionGroupNum = dataRegionGroupNum;
   }
 
-  public Integer getDataReplicationFactor() {
-    return dataReplicationFactor;
+  @Override
+  public <R, C> R accept(StatementVisitor<R, C> visitor, C context) {
+    return visitor.visitSetStorageGroup(this, context);
   }
 
-  public Long getTimePartitionInterval() {
-    return timePartitionInterval;
+  @Override
+  public QueryType getQueryType() {
+    return QueryType.WRITE;
+  }
+
+  @Override
+  public List<PartialPath> getPaths() {
+    return storageGroupPath != null
+        ? Collections.singletonList(storageGroupPath)
+        : Collections.emptyList();
   }
 
   @Override
@@ -104,13 +122,17 @@ public class SetStorageGroupStatement extends Statement implements IConfigStatem
         + "storageGroupPath="
         + storageGroupPath
         + ", ttl="
-        + ttl
+        + TTL
         + ", schemaReplicationFactor="
         + schemaReplicationFactor
         + ", dataReplicationFactor="
         + dataReplicationFactor
         + ", timePartitionInterval="
         + timePartitionInterval
+        + ", schemaRegionGroupNum="
+        + schemaRegionGroupNum
+        + ", dataRegionGroupNum="
+        + dataRegionGroupNum
         + '}';
   }
 }
diff --git a/thrift-confignode/src/main/thrift/confignode.thrift b/thrift-confignode/src/main/thrift/confignode.thrift
index b8dd2ee758..437be776a6 100644
--- a/thrift-confignode/src/main/thrift/confignode.thrift
+++ b/thrift-confignode/src/main/thrift/confignode.thrift
@@ -190,8 +190,10 @@ struct TStorageGroupSchema {
   3: optional i32 schemaReplicationFactor
   4: optional i32 dataReplicationFactor
   5: optional i64 timePartitionInterval
-  6: optional i32 maxSchemaRegionGroupNum
-  7: optional i32 maxDataRegionGroupNum
+  6: optional i32 minSchemaRegionGroupNum
+  7: optional i32 maxSchemaRegionGroupNum
+  8: optional i32 minDataRegionGroupNum
+  9: optional i32 maxDataRegionGroupNum
 }
 
 // Schema
@@ -339,10 +341,9 @@ struct TClusterParameters {
   9: required string readConsistencyLevel
   10: required double schemaRegionPerDataNode
   11: required double dataRegionPerProcessor
-  12: required i32 leastDataRegionGroupNum
-  13: required i32 seriesPartitionSlotNum
-  14: required string seriesPartitionExecutorClass
-  15: required double diskSpaceWarningThreshold
+  12: required i32 seriesPartitionSlotNum
+  13: required string seriesPartitionExecutorClass
+  14: required double diskSpaceWarningThreshold
 }
 
 struct TConfigNodeRegisterReq {