You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ja...@apache.org on 2021/10/29 00:54:49 UTC

[iotdb] branch new_vector updated: [To new_vector] Refactor aligned timeseries creation and eliminate VectorMeasurementSchema in metadata module (#4255)

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

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


The following commit(s) were added to refs/heads/new_vector by this push:
     new b1b5ea6  [To new_vector] Refactor aligned timeseries creation and eliminate VectorMeasurementSchema in metadata module (#4255)
b1b5ea6 is described below

commit b1b5ea64b46b4e18e815d58e0add8be2ee7b7595
Author: Marcos_Zyk <38...@users.noreply.github.com>
AuthorDate: Fri Oct 29 08:54:22 2021 +0800

    [To new_vector] Refactor aligned timeseries creation and eliminate VectorMeasurementSchema in metadata module (#4255)
---
 .../apache/iotdb/cluster/metadata/CMManager.java   |  12 +-
 .../iotdb/cluster/query/LocalQueryExecutor.java    |   3 +-
 .../cross/inplace/recover/LogAnalyzer.java         |   2 +-
 .../engine/storagegroup/StorageGroupProcessor.java |  80 +----
 .../org/apache/iotdb/db/metadata/MManager.java     | 354 ++++++------------
 .../db/metadata/lastCache/LastCacheManager.java    | 127 ++-----
 .../lastCache/container/ILastCacheContainer.java   |  13 -
 .../lastCache/container/LastCacheContainer.java    |  52 +--
 .../lastCache/container/value/ILastCacheValue.java |  12 -
 ...naryLastCacheValue.java => LastCacheValue.java} |  55 +--
 .../container/value/VectorLastCacheValue.java      |  86 -----
 .../iotdb/db/metadata/mnode/EntityMNode.java       |  12 +
 .../iotdb/db/metadata/mnode/IEntityMNode.java      |   4 +
 .../iotdb/db/metadata/mnode/IMeasurementMNode.java |  10 -
 .../iotdb/db/metadata/mnode/MeasurementMNode.java  |  60 +---
 .../db/metadata/mnode/MultiMeasurementMNode.java   |  65 ----
 .../db/metadata/mnode/UnaryMeasurementMNode.java   |  63 ----
 .../org/apache/iotdb/db/metadata/mtree/MTree.java  | 397 +++++++++++----------
 .../mtree/traverser/PathGrouperByStorageGroup.java | 103 ------
 .../collector/BelongedEntityPathCollector.java     |  83 -----
 ...tityPathCollector.java => EntityCollector.java} |  24 +-
 .../collector/FlatMeasurementCollector.java        | 138 -------
 .../collector/FlatMeasurementPathCollector.java    |  60 ----
 .../collector/FlatMeasurementSchemaCollector.java  | 117 ------
 .../traverser/collector/MeasurementCollector.java  |  21 +-
 ...thCollector.java => StorageGroupCollector.java} |  17 +-
 .../traverser/counter/FlatMeasurementCounter.java  |  78 ----
 .../iotdb/db/metadata/template/Template.java       | 110 +-----
 .../apache/iotdb/db/qp/executor/PlanExecutor.java  |   5 +-
 .../iotdb/db/qp/logical/crud/QueryOperator.java    |   2 +-
 .../qp/strategy/optimizer/ConcatPathOptimizer.java |   2 +-
 .../apache/iotdb/db/qp/utils/WildcardsRemover.java |   2 +-
 .../iotdb/db/query/executor/LastQueryExecutor.java |  29 +-
 .../org/apache/iotdb/db/service/TSServiceImpl.java |   2 +-
 .../iotdb/db/metadata/MManagerAdvancedTest.java    |  26 +-
 .../iotdb/db/metadata/MManagerBasicTest.java       | 119 +-----
 .../org/apache/iotdb/db/metadata/MTreeTest.java    |  20 +-
 37 files changed, 501 insertions(+), 1864 deletions(-)

diff --git a/cluster/src/main/java/org/apache/iotdb/cluster/metadata/CMManager.java b/cluster/src/main/java/org/apache/iotdb/cluster/metadata/CMManager.java
index ecd9736..8b702fa 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/metadata/CMManager.java
+++ b/cluster/src/main/java/org/apache/iotdb/cluster/metadata/CMManager.java
@@ -390,7 +390,7 @@ public class CMManager extends MManager {
       IMeasurementMNode measurementMNode = mRemoteMetaCache.get(seriesPath);
       if (measurementMNode != null) {
         LastCacheManager.updateLastCache(
-            seriesPath, timeValuePair, highPriorityUpdate, latestFlushedTime, measurementMNode);
+            measurementMNode, timeValuePair, highPriorityUpdate, latestFlushedTime);
       }
     } finally {
       cacheLock.writeLock().unlock();
@@ -403,7 +403,7 @@ public class CMManager extends MManager {
   public TimeValuePair getLastCache(PartialPath seriesPath) {
     IMeasurementMNode measurementMNode = mRemoteMetaCache.get(seriesPath);
     if (measurementMNode != null) {
-      return LastCacheManager.getLastCache(seriesPath, measurementMNode);
+      return LastCacheManager.getLastCache(measurementMNode);
     }
 
     return super.getLastCache(seriesPath);
@@ -1020,9 +1020,9 @@ public class CMManager extends MManager {
   private List<PartialPath> getMatchedPathsLocally(PartialPath partialPath, boolean withAlias)
       throws MetadataException {
     if (!withAlias) {
-      return getFlatMeasurementPaths(partialPath);
+      return getMeasurementPaths(partialPath);
     } else {
-      return super.getFlatMeasurementPathsWithAlias(partialPath, -1, -1).left;
+      return super.getMeasurementPathsWithAlias(partialPath, -1, -1).left;
     }
   }
 
@@ -1219,7 +1219,7 @@ public class CMManager extends MManager {
 
   /** Similar to method getAllTimeseriesPath(), but return Path with alias alias. */
   @Override
-  public Pair<List<PartialPath>, Integer> getFlatMeasurementPathsWithAlias(
+  public Pair<List<PartialPath>, Integer> getMeasurementPathsWithAlias(
       PartialPath pathPattern, int limit, int offset) throws MetadataException {
     Map<String, String> sgPathMap = groupPathByStorageGroup(pathPattern);
     List<PartialPath> result = getMatchedPaths(sgPathMap, true);
@@ -1699,7 +1699,7 @@ public class CMManager extends MManager {
 
     for (String path : paths) {
       List<PartialPath> allTimeseriesPathWithAlias =
-          super.getFlatMeasurementPathsWithAlias(new PartialPath(path), -1, -1).left;
+          super.getMeasurementPathsWithAlias(new PartialPath(path), -1, -1).left;
       for (PartialPath timeseriesPathWithAlias : allTimeseriesPathWithAlias) {
         retPaths.add(getPathStrListForRequest(timeseriesPathWithAlias));
         if (withAlias) {
diff --git a/cluster/src/main/java/org/apache/iotdb/cluster/query/LocalQueryExecutor.java b/cluster/src/main/java/org/apache/iotdb/cluster/query/LocalQueryExecutor.java
index 880866c..d99b3c4 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/query/LocalQueryExecutor.java
+++ b/cluster/src/main/java/org/apache/iotdb/cluster/query/LocalQueryExecutor.java
@@ -749,8 +749,7 @@ public class LocalQueryExecutor {
     List<String> result = new ArrayList<>();
     for (String seriesPath : timeseriesList) {
       try {
-        List<PartialPath> path =
-            getCMManager().getFlatMeasurementPaths(new PartialPath(seriesPath));
+        List<PartialPath> path = getCMManager().getMeasurementPaths(new PartialPath(seriesPath));
         if (path.size() != 1) {
           throw new MetadataException(
               String.format("Timeseries number of the name [%s] is not 1.", seriesPath));
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/compaction/cross/inplace/recover/LogAnalyzer.java b/server/src/main/java/org/apache/iotdb/db/engine/compaction/cross/inplace/recover/LogAnalyzer.java
index 25ec908..f1a0124 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/compaction/cross/inplace/recover/LogAnalyzer.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/compaction/cross/inplace/recover/LogAnalyzer.java
@@ -103,7 +103,7 @@ public class LogAnalyzer {
         analyzeUnseqFiles(bufferedReader);
 
         List<PartialPath> storageGroupPaths =
-            IoTDB.metaManager.getFlatMeasurementPaths(new PartialPath(storageGroupName + ".*"));
+            IoTDB.metaManager.getMeasurementPaths(new PartialPath(storageGroupName + ".*"));
         unmergedPaths = new ArrayList<>();
         unmergedPaths.addAll(storageGroupPaths);
 
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
index a48d308..dc3da15 100755
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
@@ -57,7 +57,6 @@ import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.exception.query.OutOfTTLException;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.VectorPartialPath;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
 import org.apache.iotdb.db.qp.physical.crud.DeletePlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
@@ -1106,38 +1105,16 @@ public class StorageGroupProcessor {
       }
       // Update cached last value with high priority
       if (mNodes[i] == null) {
-        if (plan.isAligned()) {
-          IoTDB.metaManager.updateLastCache(
-              new VectorPartialPath(plan.getPrefixPath(), plan.getMeasurements()[i]),
-              plan.composeLastTimeValuePair(i),
-              true,
-              latestFlushedTime);
-        } else {
-          IoTDB.metaManager.updateLastCache(
-              plan.getPrefixPath().concatNode(plan.getMeasurements()[i]),
-              plan.composeLastTimeValuePair(i),
-              true,
-              latestFlushedTime);
-        }
+        IoTDB.metaManager.updateLastCache(
+            plan.getPrefixPath().concatNode(plan.getMeasurements()[i]),
+            plan.composeLastTimeValuePair(i),
+            true,
+            latestFlushedTime);
       } else {
-        if (plan.isAligned()) {
-          // vector lastCache update need subMeasurement
-          IoTDB.metaManager.updateLastCache(
-              mNodes[i].getAsMultiMeasurementMNode(),
-              plan.getMeasurements()[i],
-              plan.composeLastTimeValuePair(i),
-              true,
-              latestFlushedTime);
-
-        } else {
-          // in stand alone version, the seriesPath is not needed, just use measurementMNodes[i] to
-          // update last cache
-          IoTDB.metaManager.updateLastCache(
-              mNodes[i].getAsUnaryMeasurementMNode(),
-              plan.composeLastTimeValuePair(i),
-              true,
-              latestFlushedTime);
-        }
+        // in stand alone version, the seriesPath is not needed, just use measurementMNodes[i] to
+        // update last cache
+        IoTDB.metaManager.updateLastCache(
+            mNodes[i], plan.composeLastTimeValuePair(i), true, latestFlushedTime);
       }
     }
   }
@@ -1185,37 +1162,16 @@ public class StorageGroupProcessor {
       }
       // Update cached last value with high priority
       if (mNodes[i] == null) {
-        if (plan.isAligned()) {
-          IoTDB.metaManager.updateLastCache(
-              new VectorPartialPath(plan.getPrefixPath(), plan.getMeasurements()[i]),
-              plan.composeTimeValuePair(i),
-              true,
-              latestFlushedTime);
-        } else {
-          IoTDB.metaManager.updateLastCache(
-              plan.getPrefixPath().concatNode(plan.getMeasurements()[i]),
-              plan.composeTimeValuePair(i),
-              true,
-              latestFlushedTime);
-        }
+        IoTDB.metaManager.updateLastCache(
+            plan.getPrefixPath().concatNode(plan.getMeasurements()[i]),
+            plan.composeTimeValuePair(i),
+            true,
+            latestFlushedTime);
       } else {
-        if (plan.isAligned()) {
-          // vector lastCache update need subSensor path
-          IoTDB.metaManager.updateLastCache(
-              mNodes[i].getAsMultiMeasurementMNode(),
-              plan.getMeasurements()[i],
-              plan.composeTimeValuePair(i),
-              true,
-              latestFlushedTime);
-        } else {
-          // in stand alone version, the seriesPath is not needed, just use measurementMNodes[i] to
-          // update last cache
-          IoTDB.metaManager.updateLastCache(
-              mNodes[i].getAsUnaryMeasurementMNode(),
-              plan.composeTimeValuePair(i),
-              true,
-              latestFlushedTime);
-        }
+        // in stand alone version, the seriesPath is not needed, just use measurementMNodes[i] to
+        // update last cache
+        IoTDB.metaManager.updateLastCache(
+            mNodes[i], plan.composeTimeValuePair(i), true, latestFlushedTime);
       }
     }
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
index 455d1d5..9340f85 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
@@ -43,8 +43,6 @@ import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
 import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.MultiMeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.UnaryMeasurementMNode;
 import org.apache.iotdb.db.metadata.mtree.MTree;
 import org.apache.iotdb.db.metadata.tag.TagManager;
 import org.apache.iotdb.db.metadata.template.Template;
@@ -92,7 +90,6 @@ import org.apache.iotdb.tsfile.utils.Pair;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.schema.TimeseriesSchema;
 import org.apache.iotdb.tsfile.write.schema.UnaryMeasurementSchema;
-import org.apache.iotdb.tsfile.write.schema.VectorMeasurementSchema;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -625,11 +622,7 @@ public class MManager {
   }
 
   /**
-   * Delete all timeseries matching the given path pattern, may cross different storage group The
-   * given pathPattern only match measurement but not flat measurement. For example, given MTree:
-   * root.sg.d.vector(s1, s2), root.sg.d.s2; give pathPattern root.**.s2 and then only root.sg.d.s2
-   * will be deleted; give pathPattern like root.sg.d.* or root.sg.d.vector and then the deletion
-   * will work on root.sg.d.vector(s1, s2)
+   * Delete all timeseries matching the given path pattern, may cross different storage group
    *
    * @param pathPattern path to be deleted
    * @return deletion failed Timeseries
@@ -686,13 +679,7 @@ public class MManager {
         mtree.deleteTimeseriesAndReturnEmptyStorageGroup(path);
     // if one of the aligned timeseries is deleted, pair.right could be null
     IMeasurementMNode measurementMNode = pair.right;
-    int timeseriesNum = 0;
-    if (measurementMNode.isUnaryMeasurement()) {
-      removeFromTagInvertedIndex(measurementMNode);
-      timeseriesNum = 1;
-    } else if (measurementMNode.isMultiMeasurement()) {
-      timeseriesNum += measurementMNode.getSchema().getSubMeasurementsTSDataTypeList().size();
-    }
+    removeFromTagInvertedIndex(measurementMNode);
     PartialPath storageGroupPath = pair.left;
 
     // drop trigger with no exceptions
@@ -709,7 +696,7 @@ public class MManager {
       mNodeCache.removeObject(node.getPartialPath());
       node = node.getParent();
     }
-    totalSeriesNumber.addAndGet(-timeseriesNum);
+    totalSeriesNumber.addAndGet(-1);
     if (!allowToCreateNewSeries
         && totalSeriesNumber.get() * ESTIMATED_SERIES_SIZE < MTREE_SIZE_THRESHOLD) {
       logger.info("Current series number {} come back to normal level", totalSeriesNumber);
@@ -885,14 +872,6 @@ public class MManager {
     return mtree.getAllTimeseriesCount(pathPattern);
   }
 
-  /**
-   * To calculate the count of timeseries component matching given path. The path could be a pattern
-   * of a full path, may contain wildcard.
-   */
-  public int getAllTimeseriesFlatCount(PartialPath pathPattern) throws MetadataException {
-    return mtree.getAllTimeseriesFlatCount(pathPattern);
-  }
-
   /** To calculate the count of devices for given path pattern. */
   public int getDevicesNum(PartialPath pathPattern) throws MetadataException {
     return mtree.getDevicesNum(pathPattern);
@@ -1091,7 +1070,7 @@ public class MManager {
    * @param fullPaths full path list without uniting the sub measurement under the same aligned time
    *     series.
    * @return Size of partial path list could NOT equal to the input list size. For example, the
-   *     VectorMeasurementSchema (s1,s2) would be returned once.
+   *     vector1 (s1,s2) would be returned once.
    */
   public List<PartialPath> groupVectorPaths(List<PartialPath> fullPaths) throws MetadataException {
     Map<IMNode, PartialPath> nodeToPartialPath = new LinkedHashMap<>();
@@ -1113,24 +1092,23 @@ public class MManager {
   }
 
   /**
-   * Return all flat measurement paths for given path if the path is abstract. Or return the path
-   * itself. Regular expression in this method is formed by the amalgamation of seriesPath and the
-   * character '*'.
+   * Return all measurement paths for given path if the path is abstract. Or return the path itself.
+   * Regular expression in this method is formed by the amalgamation of seriesPath and the character
+   * '*'.
    *
    * @param pathPattern can be a pattern or a full path of timeseries.
    */
-  public List<PartialPath> getFlatMeasurementPaths(PartialPath pathPattern)
-      throws MetadataException {
-    return mtree.getFlatMeasurementPaths(pathPattern);
+  public List<PartialPath> getMeasurementPaths(PartialPath pathPattern) throws MetadataException {
+    return mtree.getMeasurementPaths(pathPattern);
   }
 
   /**
-   * Similar to method getAllTimeseriesPath(), but return Path with alias and filter the result by
+   * Similar to method getMeasurementPaths(), but return Path with alias and filter the result by
    * limit and offset.
    */
-  public Pair<List<PartialPath>, Integer> getFlatMeasurementPathsWithAlias(
+  public Pair<List<PartialPath>, Integer> getMeasurementPathsWithAlias(
       PartialPath pathPattern, int limit, int offset) throws MetadataException {
-    return mtree.getFlatMeasurementPathsWithAlias(pathPattern, limit, offset);
+    return mtree.getMeasurementPathsWithAlias(pathPattern, limit, offset);
   }
 
   public List<ShowTimeSeriesResult> showTimeseries(ShowTimeSeriesPlan plan, QueryContext context)
@@ -1198,9 +1176,9 @@ public class MManager {
       ShowTimeSeriesPlan plan, QueryContext context) throws MetadataException {
     List<Pair<PartialPath, String[]>> ans;
     if (plan.isOrderByHeat()) {
-      ans = mtree.getAllFlatMeasurementSchemaByHeatOrder(plan, context);
+      ans = mtree.getAllMeasurementSchemaByHeatOrder(plan, context);
     } else {
-      ans = mtree.getAllFlatMeasurementSchema(plan);
+      ans = mtree.getAllMeasurementSchema(plan);
     }
     List<ShowTimeSeriesResult> res = new LinkedList<>();
     for (Pair<PartialPath, String[]> ansString : ans) {
@@ -1255,11 +1233,11 @@ public class MManager {
   }
 
   /**
-   * get MeasurementSchema or VectorMeasurementSchema which contains the measurement
+   * get MeasurementSchema
    *
    * @param device device path
    * @param measurement measurement name, could be vector name
-   * @return MeasurementSchema or VectorMeasurementSchema
+   * @return MeasurementSchema
    */
   public IMeasurementSchema getSeriesSchema(PartialPath device, String measurement)
       throws MetadataException {
@@ -1274,40 +1252,19 @@ public class MManager {
   }
 
   /**
-   * Get schema of paritialPath
+   * Get schema of paritialPath todo VectorPartialPath cases means get schemas of aligned timeseries
    *
    * @param fullPath (may be ParitialPath or VectorPartialPath)
-   * @return MeasurementSchema or VectorMeasurementSchema
+   * @return MeasurementSchema
    */
   public IMeasurementSchema getSeriesSchema(PartialPath fullPath) throws MetadataException {
     IMeasurementMNode leaf = getMeasurementMNode(fullPath);
     return getSeriesSchema(fullPath, leaf);
   }
 
+  // todo get schema from an entity with aligned timeseries
   protected IMeasurementSchema getSeriesSchema(PartialPath fullPath, IMeasurementMNode leaf) {
-    IMeasurementSchema schema = leaf.getSchema();
-
-    if (!(fullPath instanceof VectorPartialPath)
-        || schema == null
-        || schema.getType() != TSDataType.VECTOR) {
-      return schema;
-    }
-    List<String> measurementsInLeaf = schema.getSubMeasurementsList();
-    List<String> subMeasurements = ((VectorPartialPath) fullPath).getSubSensorsList();
-    TSDataType[] types = new TSDataType[subMeasurements.size()];
-    TSEncoding[] encodings = new TSEncoding[subMeasurements.size()];
-
-    for (int i = 0; i < subMeasurements.size(); i++) {
-      int index = measurementsInLeaf.indexOf(subMeasurements.get(i));
-      types[i] = schema.getSubMeasurementsTSDataTypeList().get(index);
-      encodings[i] = schema.getSubMeasurementsTSEncodingList().get(index);
-    }
-    String[] array = new String[subMeasurements.size()];
-    for (int i = 0; i < array.length; i++) {
-      array[i] = subMeasurements.get(i);
-    }
-    return new VectorMeasurementSchema(
-        schema.getMeasurementId(), array, types, encodings, schema.getCompressor());
+    return leaf.getSchema();
   }
 
   // attention: this path must be a device node
@@ -1689,8 +1646,7 @@ public class MManager {
    * <p>Invoking scenario: (1) after executing insertPlan (2) after reading last value from file
    * during last Query
    *
-   * @param seriesPath the PartialPath of full path from root to UnaryMeasurement or the
-   *     VectorPartialPath contains target subMeasurement
+   * @param seriesPath the PartialPath of full path from root to Measurement
    * @param timeValuePair the latest point value
    * @param highPriorityUpdate the last value from insertPlan is high priority
    * @param latestFlushedTime latest flushed time
@@ -1708,55 +1664,26 @@ public class MManager {
       return;
     }
 
-    LastCacheManager.updateLastCache(
-        seriesPath, timeValuePair, highPriorityUpdate, latestFlushedTime, node);
-  }
-
-  /**
-   * Update the last cache value in given unary MeasurementMNode. Vector lastCache operation won't
-   * work.
-   *
-   * <p>Invoking scenario: (1) after executing insertPlan (2) after reading last value from file
-   * during last Query
-   *
-   * @param node the measurementMNode holding the lastCache, must be unary measurement
-   * @param timeValuePair the latest point value
-   * @param highPriorityUpdate the last value from insertPlan is high priority
-   * @param latestFlushedTime latest flushed time
-   */
-  public void updateLastCache(
-      UnaryMeasurementMNode node,
-      TimeValuePair timeValuePair,
-      boolean highPriorityUpdate,
-      Long latestFlushedTime) {
-    LastCacheManager.updateLastCache(
-        node.getPartialPath(), timeValuePair, highPriorityUpdate, latestFlushedTime, node);
+    LastCacheManager.updateLastCache(node, timeValuePair, highPriorityUpdate, latestFlushedTime);
   }
 
   /**
-   * Update the last cache value of subMeasurement given Vector MeasurementMNode.
+   * Update the last cache value in given MeasurementMNode. work.
    *
    * <p>Invoking scenario: (1) after executing insertPlan (2) after reading last value from file
    * during last Query
    *
    * @param node the measurementMNode holding the lastCache
-   * @param subMeasurement the subMeasurement of aligned timeseries
    * @param timeValuePair the latest point value
    * @param highPriorityUpdate the last value from insertPlan is high priority
    * @param latestFlushedTime latest flushed time
    */
   public void updateLastCache(
-      MultiMeasurementMNode node,
-      String subMeasurement,
+      IMeasurementMNode node,
       TimeValuePair timeValuePair,
       boolean highPriorityUpdate,
       Long latestFlushedTime) {
-    LastCacheManager.updateLastCache(
-        new VectorPartialPath(node.getPartialPath(), subMeasurement),
-        timeValuePair,
-        highPriorityUpdate,
-        latestFlushedTime,
-        node);
+    LastCacheManager.updateLastCache(node, timeValuePair, highPriorityUpdate, latestFlushedTime);
   }
 
   /**
@@ -1765,8 +1692,7 @@ public class MManager {
    *
    * <p>Invoking scenario: last cache read during last Query
    *
-   * @param seriesPath the PartialPath of full path from root to UnaryMeasurement or the
-   *     VectorPartialPath contains target subMeasurement
+   * @param seriesPath the PartialPath of full path from root to Measurement
    * @return the last cache value
    */
   public TimeValuePair getLastCache(PartialPath seriesPath) {
@@ -1778,42 +1704,26 @@ public class MManager {
       return null;
     }
 
-    return LastCacheManager.getLastCache(seriesPath, node);
+    return LastCacheManager.getLastCache(node);
   }
 
   /**
-   * Get the last cache value in given unary MeasurementMNode. Vector case won't work.
-   *
-   * <p>Invoking scenario: last cache read during last Query
-   *
-   * @param node the measurementMNode holding the lastCache, must be unary measurement
-   * @return the last cache value
-   */
-  public TimeValuePair getLastCache(UnaryMeasurementMNode node) {
-    return LastCacheManager.getLastCache(node.getPartialPath(), node);
-  }
-
-  /**
-   * Get the last cache value of given subMeasurement of given MeasurementMNode. Must be Vector
-   * case.
+   * Get the last cache value in given MeasurementMNode.
    *
    * <p>Invoking scenario: last cache read during last Query
    *
    * @param node the measurementMNode holding the lastCache
-   * @param subMeasurement the subMeasurement of aligned timeseries
    * @return the last cache value
    */
-  public TimeValuePair getLastCache(MultiMeasurementMNode node, String subMeasurement) {
-    return LastCacheManager.getLastCache(
-        new VectorPartialPath(node.getPartialPath(), subMeasurement), node);
+  public TimeValuePair getLastCache(IMeasurementMNode node) {
+    return LastCacheManager.getLastCache(node);
   }
 
   /**
    * Reset the last cache value of time series of given seriesPath. MManager will use the seriesPath
    * to search the node.
    *
-   * @param seriesPath the PartialPath of full path from root to UnaryMeasurement or the
-   *     VectorPartialPath contains target subMeasurement
+   * @param seriesPath the PartialPath of full path from root to Measurement
    */
   public void resetLastCache(PartialPath seriesPath) {
     IMeasurementMNode node;
@@ -1824,7 +1734,7 @@ public class MManager {
       return;
     }
 
-    LastCacheManager.resetLastCache(seriesPath, node);
+    LastCacheManager.resetLastCache(node);
   }
 
   /**
@@ -1868,98 +1778,40 @@ public class MManager {
   @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
   public IMNode getSeriesSchemasAndReadLockDevice(InsertPlan plan)
       throws MetadataException, IOException {
-    PartialPath prefixPath = plan.getPrefixPath();
-    PartialPath deviceId = prefixPath;
-    String vectorId = null;
-    if (plan.isAligned()) {
-      deviceId = prefixPath.getDevicePath();
-      vectorId = prefixPath.getMeasurement();
-    }
+    PartialPath devicePath = plan.getPrefixPath();
     String[] measurementList = plan.getMeasurements();
     IMeasurementMNode[] measurementMNodes = plan.getMeasurementMNodes();
 
     // 1. get device node
-    IMNode deviceMNode = getDeviceNodeWithAutoCreate(deviceId);
+    IMNode deviceMNode = getDeviceNodeWithAutoCreate(devicePath);
 
     // check insert non-aligned InsertPlan for aligned timeseries
-    if (deviceMNode.isMeasurement()
-        && deviceMNode.getAsMeasurementMNode().getSchema() instanceof VectorMeasurementSchema
-        && !plan.isAligned()) {
-      throw new MetadataException(
-          String.format(
-              "Path [%s] is an aligned timeseries, please set InsertPlan.isAligned() = true",
-              prefixPath));
-    }
-    // check insert aligned InsertPlan for non-aligned timeseries
-    else if (plan.isAligned()
-        && deviceMNode.getChild(vectorId) != null
-        && !(deviceMNode.getChild(vectorId).isMeasurement())) {
+    if (plan.isAligned() && deviceMNode.isEntity() && !deviceMNode.getAsEntityMNode().isAligned()) {
       throw new MetadataException(
           String.format(
-              "Path [%s] is not an aligned timeseries, please set InsertPlan.isAligned() = false",
-              prefixPath));
+              "Timeseries under path [%s] is not aligned , please set InsertPlan.isAligned() = false",
+              plan.getPrefixPath()));
     }
 
     // 2. get schema of each measurement
-    // if do not have measurement
     IMeasurementMNode measurementMNode;
     for (int i = 0; i < measurementList.length; i++) {
       try {
-        String measurement = measurementList[i];
-        measurementMNode =
-            getMeasurementMNode(deviceMNode, plan.isAligned() ? vectorId : measurement);
-        if (measurementMNode == null) {
-          measurementMNode = findTemplate(deviceMNode, measurement, vectorId);
-        }
-        if (measurementMNode == null) {
-          if (!config.isAutoCreateSchemaEnabled()) {
-            throw new PathNotExistException(deviceId + PATH_SEPARATOR + measurement);
-          } else {
-            if (plan instanceof InsertRowPlan || plan instanceof InsertTabletPlan) {
-              if (!plan.isAligned()) {
-                internalCreateTimeseries(
-                    prefixPath.concatNode(measurement), plan.getDataTypes()[i]);
-                // after creating timeseries, the deviceMNode has been replaced by a new entityMNode
-                deviceMNode = mtree.getNodeByPath(deviceId);
-                measurementMNode = deviceMNode.getChild(measurement).getAsMeasurementMNode();
-              } else {
-                internalAlignedCreateTimeseries(
-                    prefixPath, Arrays.asList(measurementList), Arrays.asList(plan.getDataTypes()));
-                // after creating timeseries, the deviceMNode has been replaced by a new entityMNode
-                deviceMNode = mtree.getNodeByPath(deviceId);
-                measurementMNode = deviceMNode.getChild(vectorId).getAsMeasurementMNode();
-              }
-            } else {
-              throw new MetadataException(
-                  String.format(
-                      "Only support insertRow and insertTablet, plan is [%s]",
-                      plan.getOperatorType()));
-            }
-          }
-        }
+        // get MeasurementMNode, auto create if absent
+        Pair<IMNode, IMeasurementMNode> pair =
+            getMeasurementMNodeForInsertPlan(plan, i, deviceMNode);
+        deviceMNode = pair.left;
+        measurementMNode = pair.right;
 
         // check type is match
-        TSDataType insertDataType;
         if (plan instanceof InsertRowPlan || plan instanceof InsertTabletPlan) {
-          if (plan.isAligned()) {
-            TSDataType dataTypeInNode =
-                measurementMNode.getSchema().getSubMeasurementsTSDataTypeList().get(i);
-            insertDataType = plan.getDataTypes()[i];
-            if (insertDataType == null) {
-              insertDataType = dataTypeInNode;
-            }
-            if (dataTypeInNode != insertDataType) {
-              logger.warn(
-                  "DataType mismatch, Insert measurement {} in {} type {}, metadata tree type {}",
-                  measurementMNode.getSchema().getSubMeasurementsList().get(i),
-                  measurementList[i],
-                  insertDataType,
-                  dataTypeInNode);
-              DataTypeMismatchException mismatchException =
-                  new DataTypeMismatchException(measurementList[i], insertDataType, dataTypeInNode);
-              if (!config.isEnablePartialInsert()) {
-                throw mismatchException;
-              } else {
+          try {
+            checkDataTypeMatch(plan, i, measurementMNode.getSchema().getType());
+          } catch (DataTypeMismatchException mismatchException) {
+            if (!config.isEnablePartialInsert()) {
+              throw mismatchException;
+            } else {
+              if (plan.isAligned()) {
                 // mark failed measurement
                 plan.markFailedMeasurementAlignedInsertion(mismatchException);
                 for (int j = 0; j < i; j++) {
@@ -1967,53 +1819,28 @@ public class MManager {
                   measurementMNodes[j] = null;
                 }
                 break;
-              }
-            }
-            measurementMNodes[i] = measurementMNode;
-          } else {
-            if (plan instanceof InsertRowPlan) {
-              if (!((InsertRowPlan) plan).isNeedInferType()) {
-                // only when InsertRowPlan's values is object[], we should check type
-                insertDataType = getTypeInLoc(plan, i);
-              } else {
-                insertDataType = measurementMNode.getSchema().getType();
-              }
-            } else {
-              insertDataType = getTypeInLoc(plan, i);
-            }
-            if (measurementMNode.getSchema().getType() != insertDataType) {
-              logger.warn(
-                  "DataType mismatch, Insert measurement {} type {}, metadata tree type {}",
-                  measurementList[i],
-                  insertDataType,
-                  measurementMNode.getSchema().getType());
-              DataTypeMismatchException mismatchException =
-                  new DataTypeMismatchException(
-                      measurementList[i], insertDataType, measurementMNode.getSchema().getType());
-              if (!config.isEnablePartialInsert()) {
-                throw mismatchException;
               } else {
                 // mark failed measurement
                 plan.markFailedMeasurementInsertion(i, mismatchException);
                 continue;
               }
             }
-            measurementMNodes[i] = measurementMNode;
-            // set measurementName instead of alias
-            measurementList[i] = measurementMNode.getName();
           }
+          measurementMNodes[i] = measurementMNode;
+          // set measurementName instead of alias
+          measurementList[i] = measurementMNode.getName();
         }
       } catch (MetadataException e) {
         if (IoTDB.isClusterMode()) {
           logger.debug(
               "meet error when check {}.{}, message: {}",
-              deviceId,
+              devicePath,
               measurementList[i],
               e.getMessage());
         } else {
           logger.warn(
               "meet error when check {}.{}, message: {}",
-              deviceId,
+              devicePath,
               measurementList[i],
               e.getMessage());
         }
@@ -2029,6 +1856,63 @@ public class MManager {
     return deviceMNode;
   }
 
+  private Pair<IMNode, IMeasurementMNode> getMeasurementMNodeForInsertPlan(
+      InsertPlan plan, int loc, IMNode deviceMNode) throws MetadataException {
+    PartialPath devicePath = plan.getPrefixPath();
+    String[] measurementList = plan.getMeasurements();
+    String measurement = measurementList[loc];
+    IMeasurementMNode measurementMNode = getMeasurementMNode(deviceMNode, measurement);
+    if (measurementMNode == null) {
+      measurementMNode = findTemplate(deviceMNode, measurement);
+    }
+    if (measurementMNode == null) {
+      if (!config.isAutoCreateSchemaEnabled()) {
+        throw new PathNotExistException(devicePath + PATH_SEPARATOR + measurement);
+      } else {
+        if (plan instanceof InsertRowPlan || plan instanceof InsertTabletPlan) {
+          if (!plan.isAligned()) {
+            internalCreateTimeseries(devicePath.concatNode(measurement), plan.getDataTypes()[loc]);
+          } else {
+            internalAlignedCreateTimeseries(
+                devicePath, Arrays.asList(measurementList), Arrays.asList(plan.getDataTypes()));
+          }
+          // after creating timeseries, the deviceMNode has been replaced by a new entityMNode
+          deviceMNode = mtree.getNodeByPath(devicePath);
+          measurementMNode = deviceMNode.getChild(measurement).getAsMeasurementMNode();
+        } else {
+          throw new MetadataException(
+              String.format(
+                  "Only support insertRow and insertTablet, plan is [%s]", plan.getOperatorType()));
+        }
+      }
+    }
+    return new Pair<>(deviceMNode, measurementMNode);
+  }
+
+  private void checkDataTypeMatch(InsertPlan plan, int loc, TSDataType dataType)
+      throws MetadataException {
+    TSDataType insertDataType;
+    if (plan instanceof InsertRowPlan) {
+      if (!((InsertRowPlan) plan).isNeedInferType()) {
+        // only when InsertRowPlan's values is object[], we should check type
+        insertDataType = getTypeInLoc(plan, loc);
+      } else {
+        insertDataType = dataType;
+      }
+    } else {
+      insertDataType = getTypeInLoc(plan, loc);
+    }
+    if (dataType != insertDataType) {
+      String measurement = plan.getMeasurements()[loc];
+      logger.warn(
+          "DataType mismatch, Insert measurement {} type {}, metadata tree type {}",
+          measurement,
+          insertDataType,
+          dataType);
+      throw new DataTypeMismatchException(measurement, insertDataType, dataType);
+    }
+  }
+
   /** get dataType of plan, in loc measurements only support InsertRowPlan and InsertTabletPlan */
   private TSDataType getTypeInLoc(InsertPlan plan, int loc) throws MetadataException {
     TSDataType dataType;
@@ -2046,26 +1930,18 @@ public class MManager {
     return dataType;
   }
 
-  private IMeasurementMNode findTemplate(IMNode deviceMNode, String measurement, String vectorId)
+  private IMeasurementMNode findTemplate(IMNode deviceMNode, String measurement)
       throws MetadataException {
     Template curTemplate = deviceMNode.getUpperTemplate();
     if (curTemplate != null) {
-      Map<String, IMeasurementSchema> curTemplateMap = curTemplate.getSchemaMap();
-
-      String schemaName = vectorId != null ? vectorId : measurement;
-      IMeasurementSchema schema = curTemplateMap.get(schemaName);
+      IMeasurementSchema schema = curTemplate.getSchema(measurement);
       if (!deviceMNode.isUseTemplate()) {
         deviceMNode = setUsingSchemaTemplate(deviceMNode);
       }
 
       if (schema != null) {
-        if (schema instanceof UnaryMeasurementSchema) {
-          return MeasurementMNode.getMeasurementMNode(
-              deviceMNode.getAsEntityMNode(), measurement, schema, null);
-        } else if (schema instanceof VectorMeasurementSchema) {
-          return MeasurementMNode.getMeasurementMNode(
-              deviceMNode.getAsEntityMNode(), vectorId, schema, null);
-        }
+        return MeasurementMNode.getMeasurementMNode(
+            deviceMNode.getAsEntityMNode(), measurement, schema, null);
       }
       return null;
     }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/LastCacheManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/LastCacheManager.java
index a6c36eb..5dee57c 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/LastCacheManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/LastCacheManager.java
@@ -21,18 +21,14 @@ package org.apache.iotdb.db.metadata.lastCache;
 
 import org.apache.iotdb.db.engine.querycontext.QueryDataSource;
 import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.VectorPartialPath;
 import org.apache.iotdb.db.metadata.lastCache.container.ILastCacheContainer;
 import org.apache.iotdb.db.metadata.mnode.IEntityMNode;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
-import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.db.query.context.QueryContext;
 import org.apache.iotdb.db.query.control.QueryResourceManager;
 import org.apache.iotdb.db.query.executor.fill.LastPointReader;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
-import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
-import org.apache.iotdb.tsfile.write.schema.VectorMeasurementSchema;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,12 +45,11 @@ public class LastCacheManager {
   /**
    * get the last cache value of time series of given seriesPath
    *
-   * @param seriesPath the path of timeseries or subMeasurement of aligned timeseries
    * @param node the measurementMNode holding the lastCache When invoker only has the target
    *     seriesPath, the node could be null and MManager will search the node
    * @return the last cache value
    */
-  public static TimeValuePair getLastCache(PartialPath seriesPath, IMeasurementMNode node) {
+  public static TimeValuePair getLastCache(IMeasurementMNode node) {
     if (node == null) {
       return null;
     }
@@ -62,38 +57,23 @@ public class LastCacheManager {
     checkIsTemplateLastCacheAndSetIfAbsent(node);
 
     ILastCacheContainer lastCacheContainer = node.getLastCacheContainer();
-    if (seriesPath == null) {
-      return lastCacheContainer.getCachedLast();
-    } else if (seriesPath instanceof VectorPartialPath) {
-      IMeasurementSchema schema = node.getSchema();
-      if (schema instanceof VectorMeasurementSchema) {
-        return lastCacheContainer.getCachedLast(
-            node.getSchema()
-                .getSubMeasurementIndex(
-                    ((VectorPartialPath) seriesPath).getSubSensorsList().get(0)));
-      }
-      return null;
-    } else {
-      return lastCacheContainer.getCachedLast();
-    }
+    return lastCacheContainer.getCachedLast();
   }
 
   /**
    * update the last cache value of time series of given seriesPath
    *
-   * @param seriesPath the path of timeseries or subMeasurement of aligned timeseries
+   * @param node the measurementMNode holding the lastCache When invoker only has the target
+   *     seriesPath, the node could be null and MManager will search the node
    * @param timeValuePair the latest point value
    * @param highPriorityUpdate the last value from insertPlan is high priority
    * @param latestFlushedTime latest flushed time
-   * @param node the measurementMNode holding the lastCache When invoker only has the target
-   *     seriesPath, the node could be null and MManager will search the node
    */
   public static void updateLastCache(
-      PartialPath seriesPath,
+      IMeasurementMNode node,
       TimeValuePair timeValuePair,
       boolean highPriorityUpdate,
-      Long latestFlushedTime,
-      IMeasurementMNode node) {
+      Long latestFlushedTime) {
     if (node == null) {
       return;
     }
@@ -101,34 +81,16 @@ public class LastCacheManager {
     checkIsTemplateLastCacheAndSetIfAbsent(node);
 
     ILastCacheContainer lastCacheContainer = node.getLastCacheContainer();
-    if (seriesPath == null) {
-      lastCacheContainer.updateCachedLast(timeValuePair, highPriorityUpdate, latestFlushedTime);
-    } else if (seriesPath instanceof VectorPartialPath) {
-      IMeasurementSchema schema = node.getSchema();
-      if (schema instanceof VectorMeasurementSchema) {
-        if (lastCacheContainer.isEmpty()) {
-          lastCacheContainer.init(schema.getSubMeasurementsCount());
-        }
-        lastCacheContainer.updateCachedLast(
-            schema.getSubMeasurementIndex(
-                ((VectorPartialPath) seriesPath).getSubSensorsList().get(0)),
-            timeValuePair,
-            highPriorityUpdate,
-            latestFlushedTime);
-      }
-    } else {
-      lastCacheContainer.updateCachedLast(timeValuePair, highPriorityUpdate, latestFlushedTime);
-    }
+    lastCacheContainer.updateCachedLast(timeValuePair, highPriorityUpdate, latestFlushedTime);
   }
 
   /**
    * reset the last cache value of time series of given seriesPath
    *
-   * @param seriesPath the path of timeseries or subMeasurement of aligned timeseries
    * @param node the measurementMNode holding the lastCache When invoker only has the target
    *     seriesPath, the node could be null and MManager will search the node
    */
-  public static void resetLastCache(PartialPath seriesPath, IMeasurementMNode node) {
+  public static void resetLastCache(IMeasurementMNode node) {
     if (node == null) {
       return;
     }
@@ -136,21 +98,7 @@ public class LastCacheManager {
     checkIsTemplateLastCacheAndSetIfAbsent(node);
 
     ILastCacheContainer lastCacheContainer = node.getLastCacheContainer();
-    if (seriesPath == null) {
-      lastCacheContainer.resetLastCache();
-    } else if (seriesPath instanceof VectorPartialPath) {
-      IMeasurementSchema schema = node.getSchema();
-      if (schema instanceof VectorMeasurementSchema) {
-        if (lastCacheContainer.isEmpty()) {
-          lastCacheContainer.init(schema.getSubMeasurementsCount());
-        }
-        lastCacheContainer.resetLastCache(
-            schema.getSubMeasurementIndex(
-                ((VectorPartialPath) seriesPath).getSubSensorsList().get(0)));
-      }
-    } else {
-      lastCacheContainer.resetLastCache();
-    }
+    lastCacheContainer.resetLastCache();
   }
 
   private static void checkIsTemplateLastCacheAndSetIfAbsent(IMeasurementMNode node) {
@@ -164,10 +112,6 @@ public class LastCacheManager {
     // if entityMNode doesn't have this child, the child is derived from template
     if (!entityMNode.hasChild(measurement)) {
       ILastCacheContainer lastCacheContainer = entityMNode.getLastCacheContainer(measurement);
-      IMeasurementSchema schema = node.getSchema();
-      if (lastCacheContainer.isEmpty() && (schema instanceof VectorMeasurementSchema)) {
-        lastCacheContainer.init(schema.getSubMeasurementsCount());
-      }
       node.setLastCacheContainer(lastCacheContainer);
     }
   }
@@ -212,7 +156,6 @@ public class LastCacheManager {
   public static void deleteLastCacheByDevice(
       IEntityMNode node, PartialPath originalPath, long startTime, long endTime) {
     PartialPath path;
-    IMeasurementSchema schema;
     ILastCacheContainer lastCacheContainer;
 
     // process lastCache of timeseries represented by measurementNode
@@ -228,13 +171,11 @@ public class LastCacheManager {
         if (lastCacheContainer == null) {
           continue;
         }
-        schema = measurementMNode.getSchema();
-        deleteLastCache(path, schema, lastCacheContainer, startTime, endTime);
+        deleteLastCache(path, lastCacheContainer, startTime, endTime);
       }
     }
 
     // process lastCache of timeseries represented by template
-    Template template = node.getUpperTemplate();
     for (Map.Entry<String, ILastCacheContainer> entry : node.getTemplateLastCaches().entrySet()) {
       path = node.getPartialPath().concatNode(entry.getKey());
       if (originalPath.matchFullPath(path)) {
@@ -242,45 +183,21 @@ public class LastCacheManager {
         if (lastCacheContainer == null) {
           continue;
         }
-        schema = template.getSchemaMap().get(entry.getKey());
-        deleteLastCache(path, schema, lastCacheContainer, startTime, endTime);
+        deleteLastCache(path, lastCacheContainer, startTime, endTime);
       }
     }
   }
 
   private static void deleteLastCache(
-      PartialPath path,
-      IMeasurementSchema schema,
-      ILastCacheContainer lastCacheContainer,
-      long startTime,
-      long endTime) {
-    TimeValuePair lastPair;
-    if (schema instanceof VectorMeasurementSchema) {
-      int index;
-      for (String measurement : schema.getSubMeasurementsList()) {
-        index = schema.getSubMeasurementIndex(measurement);
-        lastPair = lastCacheContainer.getCachedLast(index);
-        if (lastPair != null
-            && startTime <= lastPair.getTimestamp()
-            && lastPair.getTimestamp() <= endTime) {
-          lastCacheContainer.resetLastCache(index);
-          if (logger.isDebugEnabled()) {
-            logger.debug(
-                "[tryToDeleteLastCache] Last cache for path: {} is set to null",
-                path.concatNode(measurement).getFullPath());
-          }
-        }
-      }
-    } else {
-      lastPair = lastCacheContainer.getCachedLast();
-      if (lastPair != null
-          && startTime <= lastPair.getTimestamp()
-          && lastPair.getTimestamp() <= endTime) {
-        lastCacheContainer.resetLastCache();
-        if (logger.isDebugEnabled()) {
-          logger.debug(
-              "[tryToDeleteLastCache] Last cache for path: {} is set to null", path.getFullPath());
-        }
+      PartialPath path, ILastCacheContainer lastCacheContainer, long startTime, long endTime) {
+    TimeValuePair lastPair = lastCacheContainer.getCachedLast();
+    if (lastPair != null
+        && startTime <= lastPair.getTimestamp()
+        && lastPair.getTimestamp() <= endTime) {
+      lastCacheContainer.resetLastCache();
+      if (logger.isDebugEnabled()) {
+        logger.debug(
+            "[tryToDeleteLastCache] Last cache for path: {} is set to null", path.getFullPath());
       }
     }
   }
@@ -294,9 +211,9 @@ public class LastCacheManager {
    * @return the last value
    */
   public static long getLastTimeStamp(IMeasurementMNode node, QueryContext queryContext) {
-    TimeValuePair last = getLastCache(null, node);
+    TimeValuePair last = getLastCache(node);
     if (last != null) {
-      return getLastCache(null, node).getTimestamp();
+      return getLastCache(node).getTimestamp();
     } else {
       try {
         QueryDataSource dataSource =
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/ILastCacheContainer.java b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/ILastCacheContainer.java
index 3767b51..831d930 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/ILastCacheContainer.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/ILastCacheContainer.java
@@ -24,15 +24,9 @@ import org.apache.iotdb.tsfile.read.TimeValuePair;
 /** this interface declares the operations of LastCache data */
 public interface ILastCacheContainer {
 
-  // if vector, entry need schema size to init LastCache Value list
-  void init(int size);
-
   // get lastCache of monad timseries
   TimeValuePair getCachedLast();
 
-  // get lastCache of vector timseries
-  TimeValuePair getCachedLast(int index);
-
   /**
    * update last point cache
    *
@@ -43,16 +37,9 @@ public interface ILastCacheContainer {
   void updateCachedLast(
       TimeValuePair timeValuePair, boolean highPriorityUpdate, Long latestFlushedTime);
 
-  // update lastCache for vector timseries
-  void updateCachedLast(
-      int index, TimeValuePair timeValuePair, boolean highPriorityUpdate, Long latestFlushedTime);
-
   // reset all lastCache data of one timeseries(monad or vector)
   void resetLastCache();
 
-  // reset lastCache of vector's subsensor
-  void resetLastCache(int index);
-
   // whether the entry contains lastCache Value.
   boolean isEmpty();
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/LastCacheContainer.java b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/LastCacheContainer.java
index 8ba9a99..57ce10e 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/LastCacheContainer.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/LastCacheContainer.java
@@ -20,8 +20,7 @@
 package org.apache.iotdb.db.metadata.lastCache.container;
 
 import org.apache.iotdb.db.metadata.lastCache.container.value.ILastCacheValue;
-import org.apache.iotdb.db.metadata.lastCache.container.value.UnaryLastCacheValue;
-import org.apache.iotdb.db.metadata.lastCache.container.value.VectorLastCacheValue;
+import org.apache.iotdb.db.metadata.lastCache.container.value.LastCacheValue;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
 
 /**
@@ -35,23 +34,11 @@ public class LastCacheContainer implements ILastCacheContainer {
   ILastCacheValue lastCacheValue;
 
   @Override
-  public void init(int size) {
-    if (size > 1) {
-      lastCacheValue = new VectorLastCacheValue(size);
-    }
-  }
-
-  @Override
   public TimeValuePair getCachedLast() {
     return lastCacheValue == null ? null : lastCacheValue.getTimeValuePair();
   }
 
   @Override
-  public TimeValuePair getCachedLast(int index) {
-    return lastCacheValue == null ? null : lastCacheValue.getTimeValuePair(index);
-  }
-
-  @Override
   public synchronized void updateCachedLast(
       TimeValuePair timeValuePair, boolean highPriorityUpdate, Long latestFlushedTime) {
     if (timeValuePair == null || timeValuePair.getValue() == null) {
@@ -62,8 +49,7 @@ public class LastCacheContainer implements ILastCacheContainer {
       // If no cached last, (1) a last query (2) an unseq insertion or (3) a seq insertion will
       // update cache.
       if (!highPriorityUpdate || latestFlushedTime <= timeValuePair.getTimestamp()) {
-        lastCacheValue =
-            new UnaryLastCacheValue(timeValuePair.getTimestamp(), timeValuePair.getValue());
+        lastCacheValue = new LastCacheValue(timeValuePair.getTimestamp(), timeValuePair.getValue());
       }
     } else if (timeValuePair.getTimestamp() > lastCacheValue.getTimestamp()
         || (timeValuePair.getTimestamp() == lastCacheValue.getTimestamp() && highPriorityUpdate)) {
@@ -73,45 +59,11 @@ public class LastCacheContainer implements ILastCacheContainer {
   }
 
   @Override
-  public synchronized void updateCachedLast(
-      int index, TimeValuePair timeValuePair, boolean highPriorityUpdate, Long latestFlushedTime) {
-    if (timeValuePair == null || timeValuePair.getValue() == null) {
-      return;
-    }
-
-    if (lastCacheValue.getTimeValuePair(index) == null) {
-      // If no cached last, (1) a last query (2) an unseq insertion or (3) a seq insertion will
-      // update cache.
-      if (!highPriorityUpdate || latestFlushedTime <= timeValuePair.getTimestamp()) {
-        lastCacheValue.setTimestamp(index, timeValuePair.getTimestamp());
-        lastCacheValue.setValue(index, timeValuePair.getValue());
-      }
-    } else if (timeValuePair.getTimestamp() > lastCacheValue.getTimestamp(index)) {
-      lastCacheValue.setTimestamp(index, timeValuePair.getTimestamp());
-      lastCacheValue.setValue(index, timeValuePair.getValue());
-    } else if (timeValuePair.getTimestamp() == lastCacheValue.getTimestamp(index)) {
-      if (highPriorityUpdate || lastCacheValue.getValue(index) == null) {
-        lastCacheValue.setTimestamp(index, timeValuePair.getTimestamp());
-        lastCacheValue.setValue(index, timeValuePair.getValue());
-      }
-    }
-  }
-
-  @Override
   public synchronized void resetLastCache() {
     lastCacheValue = null;
   }
 
   @Override
-  public void resetLastCache(int index) {
-    if (lastCacheValue instanceof VectorLastCacheValue) {
-      lastCacheValue.setValue(index, null);
-    } else {
-      lastCacheValue = null;
-    }
-  }
-
-  @Override
   public boolean isEmpty() {
     return lastCacheValue == null;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/ILastCacheValue.java b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/ILastCacheValue.java
index e4fc716..2a0c3d0 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/ILastCacheValue.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/ILastCacheValue.java
@@ -32,16 +32,4 @@ public interface ILastCacheValue {
   void setValue(TsPrimitiveType value);
 
   TimeValuePair getTimeValuePair();
-
-  int getSize();
-
-  long getTimestamp(int index);
-
-  void setTimestamp(int index, long timestamp);
-
-  TsPrimitiveType getValue(int index);
-
-  void setValue(int index, TsPrimitiveType value);
-
-  TimeValuePair getTimeValuePair(int index);
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/UnaryLastCacheValue.java b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/LastCacheValue.java
similarity index 51%
rename from server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/UnaryLastCacheValue.java
rename to server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/LastCacheValue.java
index b8f21ce..d9fd930 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/UnaryLastCacheValue.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/LastCacheValue.java
@@ -22,16 +22,13 @@ package org.apache.iotdb.db.metadata.lastCache.container.value;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 
-public class UnaryLastCacheValue implements ILastCacheValue {
-
-  private static final String INDEX_OPERATION_ON_MONAD_EXCEPTION =
-      "Cannot operate data on any index but 0 on MonadLastCacheValue";
+public class LastCacheValue implements ILastCacheValue {
 
   private long timestamp;
 
   private TsPrimitiveType value;
 
-  public UnaryLastCacheValue(long timestamp, TsPrimitiveType value) {
+  public LastCacheValue(long timestamp, TsPrimitiveType value) {
     this.timestamp = timestamp;
     this.value = value;
   }
@@ -55,52 +52,4 @@ public class UnaryLastCacheValue implements ILastCacheValue {
   public TimeValuePair getTimeValuePair() {
     return new TimeValuePair(timestamp, value);
   }
-
-  @Override
-  public int getSize() {
-    return 1;
-  }
-
-  @Override
-  public long getTimestamp(int index) {
-    if (index == 0) {
-      return timestamp;
-    }
-    throw new RuntimeException(INDEX_OPERATION_ON_MONAD_EXCEPTION);
-  }
-
-  @Override
-  public void setTimestamp(int index, long timestamp) {
-    if (index == 0) {
-      this.timestamp = timestamp;
-    }
-    throw new RuntimeException(INDEX_OPERATION_ON_MONAD_EXCEPTION);
-  }
-
-  @Override
-  public TsPrimitiveType getValue(int index) {
-    if (index == 0) {
-      return value;
-    }
-    throw new RuntimeException(INDEX_OPERATION_ON_MONAD_EXCEPTION);
-  }
-
-  @Override
-  public void setValue(int index, TsPrimitiveType value) {
-    if (index == 0) {
-      this.value = value;
-    }
-    throw new RuntimeException(INDEX_OPERATION_ON_MONAD_EXCEPTION);
-  }
-
-  @Override
-  public TimeValuePair getTimeValuePair(int index) {
-    if (index != 0) {
-      throw new RuntimeException(INDEX_OPERATION_ON_MONAD_EXCEPTION);
-    } else if (value == null) {
-      return null;
-    } else {
-      return new TimeValuePair(timestamp, value);
-    }
-  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/VectorLastCacheValue.java b/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/VectorLastCacheValue.java
deleted file mode 100644
index d5a3ada..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/lastCache/container/value/VectorLastCacheValue.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.iotdb.db.metadata.lastCache.container.value;
-
-import org.apache.iotdb.tsfile.read.TimeValuePair;
-import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
-
-// this class defines the storage of vector lastCache data
-public class VectorLastCacheValue implements ILastCacheValue {
-
-  // the last point data of different subSensors may vary from each other on timestamp
-  private long[] timestamps;
-
-  private TsPrimitiveType[] values;
-
-  public VectorLastCacheValue(int size) {
-    timestamps = new long[size];
-    values = new TsPrimitiveType[size];
-  }
-
-  @Override
-  public int getSize() {
-    return values.length;
-  }
-
-  @Override
-  public long getTimestamp(int index) {
-    return timestamps[index];
-  }
-
-  @Override
-  public void setTimestamp(int index, long timestamp) {
-    timestamps[index] = timestamp;
-  }
-
-  @Override
-  public TsPrimitiveType getValue(int index) {
-    return values == null ? null : values[index];
-  }
-
-  @Override
-  public void setValue(int index, TsPrimitiveType value) {
-    values[index] = value;
-  }
-
-  @Override
-  public TimeValuePair getTimeValuePair(int index) {
-    if (values == null || index < 0 || index >= values.length || values[index] == null) {
-      return null;
-    }
-    return new TimeValuePair(timestamps[index], values[index]);
-  }
-
-  @Override
-  public long getTimestamp() {
-    return 0;
-  }
-
-  @Override
-  public void setTimestamp(long timestamp) {}
-
-  @Override
-  public void setValue(TsPrimitiveType value) {}
-
-  @Override
-  public TimeValuePair getTimeValuePair() {
-    return null;
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java
index 11e7f91..e6884c0 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/EntityMNode.java
@@ -37,6 +37,8 @@ public class EntityMNode extends InternalMNode implements IEntityMNode {
 
   private volatile boolean useTemplate = false;
 
+  private volatile boolean isAligned = false;
+
   private volatile Map<String, ILastCacheContainer> lastCacheMap = null;
 
   /**
@@ -115,6 +117,16 @@ public class EntityMNode extends InternalMNode implements IEntityMNode {
     this.useTemplate = useTemplate;
   }
 
+  @Override
+  public boolean isAligned() {
+    return isAligned;
+  }
+
+  @Override
+  public void setAligned(boolean isAligned) {
+    this.isAligned = isAligned;
+  }
+
   public ILastCacheContainer getLastCacheContainer(String measurementId) {
     checkLastCacheMap();
     return lastCacheMap.computeIfAbsent(measurementId, k -> new LastCacheContainer());
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java
index a77abe62..b34113b 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IEntityMNode.java
@@ -36,6 +36,10 @@ public interface IEntityMNode extends IMNode {
 
   void setUseTemplate(boolean useTemplate);
 
+  boolean isAligned();
+
+  void setAligned(boolean isAligned);
+
   ILastCacheContainer getLastCacheContainer(String measurementId);
 
   Map<String, ILastCacheContainer> getTemplateLastCaches();
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
index e99116b..b1bc69d 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/IMeasurementMNode.java
@@ -33,8 +33,6 @@ public interface IMeasurementMNode extends IMNode {
 
   TSDataType getDataType(String measurementId);
 
-  int getMeasurementCount();
-
   String getAlias();
 
   void setAlias(String alias);
@@ -50,12 +48,4 @@ public interface IMeasurementMNode extends IMNode {
   ILastCacheContainer getLastCacheContainer();
 
   void setLastCacheContainer(ILastCacheContainer lastCacheContainer);
-
-  boolean isUnaryMeasurement();
-
-  boolean isMultiMeasurement();
-
-  UnaryMeasurementMNode getAsUnaryMeasurementMNode();
-
-  MultiMeasurementMNode getAsMultiMeasurementMNode();
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
index e094a34..5024cf6 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MeasurementMNode.java
@@ -26,8 +26,6 @@ import org.apache.iotdb.db.metadata.template.Template;
 import org.apache.iotdb.db.qp.physical.sys.MeasurementMNodePlan;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
-import org.apache.iotdb.tsfile.write.schema.UnaryMeasurementSchema;
-import org.apache.iotdb.tsfile.write.schema.VectorMeasurementSchema;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,7 +34,7 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;
 
-public abstract class MeasurementMNode extends MNode implements IMeasurementMNode {
+public class MeasurementMNode extends MNode implements IMeasurementMNode {
 
   private static final Logger logger = LoggerFactory.getLogger(MeasurementMNode.class);
 
@@ -44,6 +42,8 @@ public abstract class MeasurementMNode extends MNode implements IMeasurementMNod
   protected String alias;
   /** tag/attribute's start offset in tag file */
   private long offset = -1;
+  /** measurement's Schema for one timeseries represented by current leaf node */
+  private IMeasurementSchema schema;
   /** last value cache */
   private volatile ILastCacheContainer lastCacheContainer = null;
   /** registered trigger */
@@ -56,22 +56,13 @@ public abstract class MeasurementMNode extends MNode implements IMeasurementMNod
    */
   public static IMeasurementMNode getMeasurementMNode(
       IEntityMNode parent, String measurementName, IMeasurementSchema schema, String alias) {
-    if (schema == null) {
-      return new UnaryMeasurementMNode(parent, measurementName, null, alias);
-    } else if (schema instanceof UnaryMeasurementSchema) {
-      return new UnaryMeasurementMNode(
-          parent, measurementName, (UnaryMeasurementSchema) schema, alias);
-    } else if (schema instanceof VectorMeasurementSchema) {
-      return new MultiMeasurementMNode(
-          parent, measurementName, (VectorMeasurementSchema) schema, alias);
-    } else {
-      throw new RuntimeException("Undefined schema type.");
-    }
+    return new MeasurementMNode(parent, measurementName, schema, alias);
   }
 
   /** @param alias alias of measurementName */
-  MeasurementMNode(IMNode parent, String name, String alias) {
+  MeasurementMNode(IMNode parent, String name, IMeasurementSchema schema, String alias) {
     super(parent, name);
+    this.schema = schema;
     this.alias = alias;
   }
 
@@ -84,10 +75,9 @@ public abstract class MeasurementMNode extends MNode implements IMeasurementMNod
   }
 
   @Override
-  public abstract IMeasurementSchema getSchema();
-
-  @Override
-  public abstract int getMeasurementCount();
+  public IMeasurementSchema getSchema() {
+    return schema;
+  }
 
   /**
    * get data type
@@ -96,7 +86,9 @@ public abstract class MeasurementMNode extends MNode implements IMeasurementMNod
    * @return measurement data type
    */
   @Override
-  public abstract TSDataType getDataType(String measurementId);
+  public TSDataType getDataType(String measurementId) {
+    return schema.getType();
+  }
 
   @Override
   public long getOffset() {
@@ -160,34 +152,6 @@ public abstract class MeasurementMNode extends MNode implements IMeasurementMNod
   }
 
   @Override
-  public boolean isUnaryMeasurement() {
-    return false;
-  }
-
-  @Override
-  public boolean isMultiMeasurement() {
-    return false;
-  }
-
-  @Override
-  public UnaryMeasurementMNode getAsUnaryMeasurementMNode() {
-    if (isUnaryMeasurement()) {
-      return (UnaryMeasurementMNode) this;
-    } else {
-      throw new UnsupportedOperationException("This is not an UnaryMeasurementMNode");
-    }
-  }
-
-  @Override
-  public MultiMeasurementMNode getAsMultiMeasurementMNode() {
-    if (isMultiMeasurement()) {
-      return (MultiMeasurementMNode) this;
-    } else {
-      throw new UnsupportedOperationException("This is not an MultiMeasurementMNode");
-    }
-  }
-
-  @Override
   public String getFullPath() {
     if (fullPath != null) {
       return fullPath;
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MultiMeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MultiMeasurementMNode.java
deleted file mode 100644
index 2c5bb5d..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/MultiMeasurementMNode.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mnode;
-
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-import org.apache.iotdb.tsfile.write.schema.VectorMeasurementSchema;
-
-import java.util.List;
-
-public class MultiMeasurementMNode extends MeasurementMNode {
-
-  /** measurement's Schema for one aligned timeseries represented by current leaf node */
-  private VectorMeasurementSchema schema;
-
-  MultiMeasurementMNode(
-      IEntityMNode parent, String measurementName, VectorMeasurementSchema schema, String alias) {
-    super(parent, measurementName, alias);
-    this.schema = schema;
-  }
-
-  @Override
-  public VectorMeasurementSchema getSchema() {
-    return schema;
-  }
-
-  public void setSchema(VectorMeasurementSchema schema) {
-    this.schema = schema;
-  }
-
-  @Override
-  public int getMeasurementCount() {
-    return schema.getSubMeasurementsCount();
-  }
-
-  @Override
-  public TSDataType getDataType(String measurementId) {
-    int index = schema.getSubMeasurementIndex(measurementId);
-    return schema.getSubMeasurementsTSDataTypeList().get(index);
-  }
-
-  public List<String> getSubMeasurementList() {
-    return schema.getSubMeasurementsList();
-  }
-
-  @Override
-  public boolean isMultiMeasurement() {
-    return true;
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/UnaryMeasurementMNode.java b/server/src/main/java/org/apache/iotdb/db/metadata/mnode/UnaryMeasurementMNode.java
deleted file mode 100644
index 82417c9..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mnode/UnaryMeasurementMNode.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mnode;
-
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-import org.apache.iotdb.tsfile.write.schema.UnaryMeasurementSchema;
-
-/** Represents an MNode which has a Measurement or Sensor attached to it. */
-public class UnaryMeasurementMNode extends MeasurementMNode {
-
-  /** measurement's Schema for one timeseries represented by current leaf node */
-  private UnaryMeasurementSchema schema;
-
-  UnaryMeasurementMNode(
-      IEntityMNode parent, String measurementName, UnaryMeasurementSchema schema, String alias) {
-    super(parent, measurementName, alias);
-    this.schema = schema;
-  }
-
-  @Override
-  public UnaryMeasurementSchema getSchema() {
-    return schema;
-  }
-
-  public void setSchema(UnaryMeasurementSchema schema) {
-    this.schema = schema;
-  }
-
-  @Override
-  public int getMeasurementCount() {
-    return 1;
-  }
-
-  @Override
-  public TSDataType getDataType(String measurementId) {
-    if (name.equals(measurementId)) {
-      return schema.getType();
-    } else {
-      throw new RuntimeException("MeasurementId mismatch in UnaryMeasurementMNode");
-    }
-  }
-
-  @Override
-  public boolean isUnaryMeasurement() {
-    return true;
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
index d51e8e7..b563c01 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
@@ -22,6 +22,7 @@ import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.engine.fileSystem.SystemFileFactory;
 import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
+import org.apache.iotdb.db.exception.metadata.AlignedTimeseriesException;
 import org.apache.iotdb.db.exception.metadata.IllegalPathException;
 import org.apache.iotdb.db.exception.metadata.MNodeTypeMismatchException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
@@ -36,17 +37,12 @@ import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.metadata.logfile.MLogReader;
 import org.apache.iotdb.db.metadata.logfile.MLogWriter;
 import org.apache.iotdb.db.metadata.mnode.*;
-import org.apache.iotdb.db.metadata.mtree.traverser.PathGrouperByStorageGroup;
-import org.apache.iotdb.db.metadata.mtree.traverser.collector.BelongedEntityPathCollector;
-import org.apache.iotdb.db.metadata.mtree.traverser.collector.EntityPathCollector;
-import org.apache.iotdb.db.metadata.mtree.traverser.collector.FlatMeasurementPathCollector;
-import org.apache.iotdb.db.metadata.mtree.traverser.collector.FlatMeasurementSchemaCollector;
+import org.apache.iotdb.db.metadata.mtree.traverser.collector.EntityCollector;
 import org.apache.iotdb.db.metadata.mtree.traverser.collector.MNodeCollector;
 import org.apache.iotdb.db.metadata.mtree.traverser.collector.MeasurementCollector;
-import org.apache.iotdb.db.metadata.mtree.traverser.collector.StorageGroupPathCollector;
+import org.apache.iotdb.db.metadata.mtree.traverser.collector.StorageGroupCollector;
 import org.apache.iotdb.db.metadata.mtree.traverser.counter.CounterTraverser;
 import org.apache.iotdb.db.metadata.mtree.traverser.counter.EntityCounter;
-import org.apache.iotdb.db.metadata.mtree.traverser.counter.FlatMeasurementCounter;
 import org.apache.iotdb.db.metadata.mtree.traverser.counter.MNodeLevelCounter;
 import org.apache.iotdb.db.metadata.mtree.traverser.counter.MeasurementCounter;
 import org.apache.iotdb.db.metadata.mtree.traverser.counter.StorageGroupCounter;
@@ -68,7 +64,6 @@ import org.apache.iotdb.tsfile.utils.Pair;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.schema.TimeseriesSchema;
 import org.apache.iotdb.tsfile.write.schema.UnaryMeasurementSchema;
-import org.apache.iotdb.tsfile.write.schema.VectorMeasurementSchema;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -99,6 +94,7 @@ import java.util.stream.Stream;
 
 import static java.util.stream.Collectors.toList;
 import static org.apache.iotdb.db.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
+import static org.apache.iotdb.db.metadata.lastCache.LastCacheManager.getLastTimeStamp;
 
 /**
  * The hierarchical struct of the Metadata Tree is implemented in this class.
@@ -329,52 +325,14 @@ public class MTree implements Serializable {
       Map<String, String> props,
       String alias)
       throws MetadataException {
-    String[] nodeNames = path.getNodes();
-    if (nodeNames.length <= 2 || !nodeNames[0].equals(root.getName())) {
-      throw new IllegalPathException(path.getFullPath());
-    }
-    MetaFormatUtils.checkTimeseries(path);
-    IMNode cur = root;
-    boolean hasSetStorageGroup = false;
-    Template upperTemplate = cur.getSchemaTemplate();
-    // e.g, path = root.sg.d1.s1,  create internal nodes and set cur to d1 node
-    for (int i = 1; i < nodeNames.length - 1; i++) {
-      if (cur.isMeasurement()) {
-        throw new PathAlreadyExistException(cur.getFullPath());
-      }
-      if (cur.isStorageGroup()) {
-        hasSetStorageGroup = true;
-      }
-      String childName = nodeNames[i];
-      if (!cur.hasChild(childName)) {
-        if (!hasSetStorageGroup) {
-          throw new StorageGroupNotSetException("Storage group should be created first");
-        }
-        if (cur.isUseTemplate() && upperTemplate.hasSchema(childName)) {
-          throw new PathAlreadyExistException(
-              cur.getPartialPath().concatNode(childName).getFullPath());
-        }
-        cur.addChild(childName, new InternalMNode(cur, childName));
-      }
-      cur = cur.getChild(childName);
-
-      if (cur.getSchemaTemplate() != null) {
-        upperTemplate = cur.getSchemaTemplate();
-      }
-    }
-
-    if (cur.isMeasurement()) {
-      throw new PathAlreadyExistException(cur.getFullPath());
-    }
-
-    if (upperTemplate != null && !upperTemplate.isCompatible(path)) {
-      throw new PathAlreadyExistException(
-          path.getFullPath() + " ( which is incompatible with template )");
-    }
+    MetaFormatUtils.checkNodeName(path.getMeasurement());
+    Pair<IMNode, Template> pair = checkAndAutoCreateInternalPath(path.getDevicePath());
+    IMNode cur = pair.left;
+    Template upperTemplate = pair.right;
 
     MetaFormatUtils.checkTimeseriesProps(path.getFullPath(), props);
 
-    String leafName = nodeNames[nodeNames.length - 1];
+    String leafName = path.getMeasurement();
 
     // synchronize check and add, we need addChild and add Alias become atomic operation
     // only write on mtree will be synchronized
@@ -387,6 +345,12 @@ public class MTree implements Serializable {
         throw new AliasAlreadyExistException(path.getFullPath(), alias);
       }
 
+      if (upperTemplate != null
+          && (upperTemplate.hasSchema(leafName) || upperTemplate.hasSchema(alias))) {
+        throw new PathAlreadyExistException(
+            path.getFullPath() + " ( which is incompatible with template )");
+      }
+
       IEntityMNode entityMNode = MNodeUtils.setToEntity(cur);
 
       IMeasurementMNode measurementMNode =
@@ -421,63 +385,89 @@ public class MTree implements Serializable {
       List<TSEncoding> encodings,
       CompressionType compressor)
       throws MetadataException {
-    String[] deviceNodeNames = devicePath.getNodes();
-    if (deviceNodeNames.length <= 1 || !deviceNodeNames[0].equals(root.getName())) {
+    MetaFormatUtils.checkSchemaMeasurementNames(measurements);
+    Pair<IMNode, Template> pair = checkAndAutoCreateInternalPath(devicePath);
+    IMNode cur = pair.left;
+    Template upperTemplate = pair.right;
+
+    // synchronize check and add, we need addChild and add Alias become atomic operation
+    // only write on mtree will be synchronized
+    synchronized (this) {
+      for (String measurement : measurements) {
+        if (cur.hasChild(measurement)) {
+          throw new PathAlreadyExistException(devicePath.getFullPath() + "." + measurement);
+        }
+      }
+
+      if (upperTemplate != null) {
+        for (String measurement : measurements) {
+          if (upperTemplate.hasSchema(measurement)) {
+            throw new PathAlreadyExistException(
+                devicePath.concatNode(measurement).getFullPath()
+                    + " ( which is incompatible with template )");
+          }
+        }
+      }
+
+      if (cur.isEntity() && !cur.getAsEntityMNode().isAligned()) {
+        throw new AlignedTimeseriesException(
+            "Aligned timeseries cannot be created under this entity", devicePath.getFullPath());
+      }
+
+      IEntityMNode entityMNode = MNodeUtils.setToEntity(cur);
+
+      for (int i = 0; i < measurements.size(); i++) {
+        IMeasurementMNode measurementMNode =
+            MeasurementMNode.getMeasurementMNode(
+                entityMNode,
+                measurements.get(i),
+                new UnaryMeasurementSchema(
+                    measurements.get(i), dataTypes.get(i), encodings.get(i), compressor),
+                null);
+        entityMNode.addChild(measurements.get(i), measurementMNode);
+      }
+      entityMNode.setAligned(true);
+    }
+  }
+
+  private Pair<IMNode, Template> checkAndAutoCreateInternalPath(PartialPath devicePath)
+      throws MetadataException {
+    String[] nodeNames = devicePath.getNodes();
+    if (nodeNames.length < 2 || !nodeNames[0].equals(root.getName())) {
       throw new IllegalPathException(devicePath.getFullPath());
     }
     MetaFormatUtils.checkTimeseries(devicePath);
-    MetaFormatUtils.checkSchemaMeasurementNames(measurements);
     IMNode cur = root;
     boolean hasSetStorageGroup = false;
-    // e.g, devicePath = root.sg.d1, create internal nodes and set cur to d1 node
-    for (int i = 1; i < deviceNodeNames.length - 1; i++) {
+    Template upperTemplate = cur.getSchemaTemplate();
+    // e.g, path = root.sg.d1.s1,  create internal nodes and set cur to d1 node
+    for (int i = 1; i < nodeNames.length; i++) {
+      String childName = nodeNames[i];
+      if (!cur.hasChild(childName)) {
+        if (!hasSetStorageGroup) {
+          throw new StorageGroupNotSetException("Storage group should be created first");
+        }
+        if (upperTemplate != null && upperTemplate.hasSchema(childName)) {
+          throw new PathAlreadyExistException(
+              cur.getPartialPath().concatNode(childName).getFullPath()
+                  + " ( which is incompatible with template )");
+        }
+        cur.addChild(childName, new InternalMNode(cur, childName));
+      }
+      cur = cur.getChild(childName);
+
       if (cur.isMeasurement()) {
         throw new PathAlreadyExistException(cur.getFullPath());
       }
       if (cur.isStorageGroup()) {
         hasSetStorageGroup = true;
       }
-      String nodeName = deviceNodeNames[i];
-      if (!cur.hasChild(nodeName)) {
-        if (!hasSetStorageGroup) {
-          throw new StorageGroupNotSetException("Storage group should be created first");
-        }
-        cur.addChild(nodeName, new InternalMNode(cur, nodeName));
-      }
-      cur = cur.getChild(nodeName);
-    }
-
-    if (cur.isMeasurement()) {
-      throw new PathAlreadyExistException(cur.getFullPath());
-    }
-
-    String leafName = deviceNodeNames[deviceNodeNames.length - 1];
 
-    // synchronize check and add, we need addChild and add Alias become atomic operation
-    // only write on mtree will be synchronized
-    synchronized (this) {
-      if (cur.hasChild(leafName)) {
-        throw new PathAlreadyExistException(devicePath.getFullPath() + "." + leafName);
+      if (cur.getSchemaTemplate() != null) {
+        upperTemplate = cur.getSchemaTemplate();
       }
-
-      IEntityMNode entityMNode = MNodeUtils.setToEntity(cur);
-
-      int measurementsSize = measurements.size();
-
-      // this measurementMNode could be a leaf or not.
-      IMeasurementMNode measurementMNode =
-          MeasurementMNode.getMeasurementMNode(
-              entityMNode,
-              leafName,
-              new VectorMeasurementSchema(
-                  leafName,
-                  measurements.toArray(new String[measurementsSize]),
-                  dataTypes.toArray(new TSDataType[measurementsSize]),
-                  encodings.toArray(new TSEncoding[measurementsSize]),
-                  compressor),
-              null);
-      entityMNode.addChild(leafName, measurementMNode);
     }
+    return new Pair<>(cur, upperTemplate);
   }
 
   /**
@@ -685,15 +675,7 @@ public class MTree implements Serializable {
       }
       cur = cur.getChild(nodeNames[i]);
       if (cur.isMeasurement()) {
-        if (i == nodeNames.length - 1) {
-          return true;
-        }
-        IMeasurementSchema schema = cur.getAsMeasurementMNode().getSchema();
-        if (schema instanceof VectorMeasurementSchema) {
-          return i == nodeNames.length - 2 && schema.containsSubMeasurement(nodeNames[i + 1]);
-        } else {
-          return false;
-        }
+        return i == nodeNames.length - 1;
       }
       upperTemplate = cur.getSchemaTemplate() == null ? upperTemplate : cur.getSchemaTemplate();
     }
@@ -776,10 +758,7 @@ public class MTree implements Serializable {
    */
   public List<PartialPath> getBelongedStorageGroups(PartialPath pathPattern)
       throws MetadataException {
-    StorageGroupPathCollector collector = new StorageGroupPathCollector(root, pathPattern);
-    collector.setCollectInternal(true);
-    collector.traverse();
-    return collector.getResult();
+    return collectStorageGroups(pathPattern, true);
   }
 
   /**
@@ -790,10 +769,22 @@ public class MTree implements Serializable {
    */
   public List<PartialPath> getMatchedStorageGroups(PartialPath pathPattern)
       throws MetadataException {
-    StorageGroupPathCollector collector = new StorageGroupPathCollector(root, pathPattern);
-    collector.setCollectInternal(false);
+    return collectStorageGroups(pathPattern, false);
+  }
+
+  private List<PartialPath> collectStorageGroups(PartialPath pathPattern, boolean collectInternal)
+      throws MetadataException {
+    List<PartialPath> result = new LinkedList<>();
+    StorageGroupCollector<List<PartialPath>> collector =
+        new StorageGroupCollector<List<PartialPath>>(root, pathPattern) {
+          @Override
+          protected void collectStorageGroup(IStorageGroupMNode node) {
+            result.add(node.getPartialPath());
+          }
+        };
+    collector.setCollectInternal(collectInternal);
     collector.traverse();
-    return collector.getResult();
+    return result;
   }
 
   /**
@@ -822,9 +813,18 @@ public class MTree implements Serializable {
    * storageGroupName-fullPath pair into paths.
    */
   public Map<String, String> groupPathByStorageGroup(PartialPath path) throws MetadataException {
-    PathGrouperByStorageGroup resolver = new PathGrouperByStorageGroup(root, path);
-    resolver.traverse();
-    return resolver.getResult();
+    Map<String, String> result = new HashMap<>();
+    StorageGroupCollector<Map<String, String>> collector =
+        new StorageGroupCollector<Map<String, String>>(root, path) {
+          @Override
+          protected void collectStorageGroup(IStorageGroupMNode node) {
+            PartialPath sgPath = node.getPartialPath();
+            result.put(sgPath.getFullPath(), path.alterPrefixPath(sgPath).getFullPath());
+          }
+        };
+    collector.setCollectInternal(true);
+    collector.traverse();
+    return result;
   }
   // endregion
 
@@ -837,34 +837,51 @@ public class MTree implements Serializable {
    */
   public Set<PartialPath> getDevices(PartialPath pathPattern, boolean isPrefixMatch)
       throws MetadataException {
-    EntityPathCollector collector = new EntityPathCollector(root, pathPattern);
+    Set<PartialPath> result = new TreeSet<>();
+    EntityCollector<Set<PartialPath>> collector =
+        new EntityCollector<Set<PartialPath>>(root, pathPattern) {
+          @Override
+          protected void collectEntity(IEntityMNode node) {
+            result.add(node.getPartialPath());
+          }
+        };
     collector.setPrefixMatch(isPrefixMatch);
     collector.traverse();
-    return collector.getResult();
+    return result;
   }
 
   public List<ShowDevicesResult> getDevices(ShowDevicesPlan plan) throws MetadataException {
-    EntityPathCollector collector =
-        new EntityPathCollector(root, plan.getPath(), plan.getLimit(), plan.getOffset());
-    collector.traverse();
-    Set<PartialPath> devices = collector.getResult();
     List<ShowDevicesResult> res = new ArrayList<>();
-    for (PartialPath device : devices) {
-      if (plan.hasSgCol()) {
-        res.add(
-            new ShowDevicesResult(
-                device.getFullPath(), getBelongedStorageGroup(device).getFullPath()));
-      } else {
-        res.add(new ShowDevicesResult(device.getFullPath()));
-      }
-    }
+    EntityCollector<List<ShowDevicesResult>> collector =
+        new EntityCollector<List<ShowDevicesResult>>(
+            root, plan.getPath(), plan.getLimit(), plan.getOffset()) {
+          @Override
+          protected void collectEntity(IEntityMNode node) throws MetadataException {
+            PartialPath device = node.getPartialPath();
+            if (plan.hasSgCol()) {
+              res.add(
+                  new ShowDevicesResult(
+                      device.getFullPath(), getBelongedStorageGroup(device).getFullPath()));
+            } else {
+              res.add(new ShowDevicesResult(device.getFullPath()));
+            }
+          }
+        };
+    collector.traverse();
     return res;
   }
 
   public Set<PartialPath> getDevicesByTimeseries(PartialPath timeseries) throws MetadataException {
-    BelongedEntityPathCollector collector = new BelongedEntityPathCollector(root, timeseries);
+    Set<PartialPath> result = new HashSet<>();
+    MeasurementCollector<Set<PartialPath>> collector =
+        new MeasurementCollector<Set<PartialPath>>(root, timeseries) {
+          @Override
+          protected void collectMeasurement(IMeasurementMNode node) throws MetadataException {
+            result.add(node.getParent().getPartialPath());
+          }
+        };
     collector.traverse();
-    return collector.getResult();
+    return result;
   }
   // endregion
 
@@ -882,58 +899,45 @@ public class MTree implements Serializable {
    * @param pathPattern a path pattern or a full path, may contain wildcard.
    */
   public List<PartialPath> getMeasurementPaths(PartialPath pathPattern) throws MetadataException {
-    MeasurementCollector<List<PartialPath>> collector =
-        new MeasurementCollector<List<PartialPath>>(root, pathPattern) {
-          @Override
-          protected void collectMeasurement(IMeasurementMNode node) {
-            resultSet.add(node.getPartialPath());
-          }
-        };
-    collector.setResultSet(new LinkedList<>());
-    collector.traverse();
-    return collector.getResult();
-  }
-
-  /**
-   * Get all flat measurement paths matching the given path pattern
-   *
-   * @param pathPattern a path pattern or a full path, may contain wildcard.
-   */
-  public List<PartialPath> getFlatMeasurementPaths(PartialPath pathPattern)
-      throws MetadataException {
-    return getFlatMeasurementPathsWithAlias(pathPattern, 0, 0).left;
+    return getMeasurementPathsWithAlias(pathPattern, 0, 0).left;
   }
 
   /**
-   * Get all flat measurement paths matching the given path pattern
+   * Get all measurement paths matching the given path pattern
    *
    * @param pathPattern a path pattern or a full path, may contain wildcard
    * @return Pair.left contains all the satisfied paths Pair.right means the current offset or zero
    *     if we don't set offset.
    */
-  public Pair<List<PartialPath>, Integer> getFlatMeasurementPathsWithAlias(
+  public Pair<List<PartialPath>, Integer> getMeasurementPathsWithAlias(
       PartialPath pathPattern, int limit, int offset) throws MetadataException {
-    FlatMeasurementPathCollector collector =
-        new FlatMeasurementPathCollector(root, pathPattern, limit, offset);
+    List<PartialPath> result = new LinkedList<>();
+    MeasurementCollector<List<PartialPath>> collector =
+        new MeasurementCollector<List<PartialPath>>(root, pathPattern, limit, offset) {
+          @Override
+          protected void collectMeasurement(IMeasurementMNode node) throws MetadataException {
+            PartialPath path = node.getPartialPath();
+            if (nodes[nodes.length - 1].equals(node.getAlias())) {
+              // only when user query with alias, the alias in path will be set
+              path.setMeasurementAlias(node.getAlias());
+            }
+            result.add(path);
+          }
+        };
     collector.traverse();
     offset = collector.getCurOffset() + 1;
-    List<PartialPath> res = collector.getResult();
-    return new Pair<>(res, offset);
+    return new Pair<>(result, offset);
   }
 
   /**
-   * Get all flat measurement schema matching the given path pattern order by insert frequency
+   * Get all measurement schema matching the given path pattern order by insert frequency
    *
    * <p>result: [name, alias, storage group, dataType, encoding, compression, offset]
    */
-  public List<Pair<PartialPath, String[]>> getAllFlatMeasurementSchemaByHeatOrder(
+  public List<Pair<PartialPath, String[]>> getAllMeasurementSchemaByHeatOrder(
       ShowTimeSeriesPlan plan, QueryContext queryContext) throws MetadataException {
-    FlatMeasurementSchemaCollector collector =
-        new FlatMeasurementSchemaCollector(root, plan.getPath());
-    collector.setQueryContext(queryContext);
-    collector.setNeedLast(true);
-    collector.traverse();
-    List<Pair<PartialPath, String[]>> allMatchedNodes = collector.getResult();
+    List<Pair<PartialPath, String[]>> allMatchedNodes =
+        collectMeasurementSchema(plan.getPath(), 0, 0, queryContext, true);
 
     Stream<Pair<PartialPath, String[]>> sortedStream =
         allMatchedNodes.stream()
@@ -952,16 +956,57 @@ public class MTree implements Serializable {
   }
 
   /**
-   * Get all flat measurement schema matching the given path pattern
+   * Get all measurement schema matching the given path pattern
    *
    * <p>result: [name, alias, storage group, dataType, encoding, compression, offset]
    */
-  public List<Pair<PartialPath, String[]>> getAllFlatMeasurementSchema(ShowTimeSeriesPlan plan)
+  public List<Pair<PartialPath, String[]>> getAllMeasurementSchema(ShowTimeSeriesPlan plan)
+      throws MetadataException {
+    return collectMeasurementSchema(plan.getPath(), plan.getLimit(), plan.getOffset(), null, false);
+  }
+
+  private List<Pair<PartialPath, String[]>> collectMeasurementSchema(
+      PartialPath pathPattern, int limit, int offset, QueryContext queryContext, boolean needLast)
       throws MetadataException {
-    FlatMeasurementSchemaCollector collector =
-        new FlatMeasurementSchemaCollector(root, plan.getPath(), plan.getLimit(), plan.getOffset());
+    List<Pair<PartialPath, String[]>> result = new LinkedList<>();
+    MeasurementCollector<List<Pair<PartialPath, String[]>>> collector =
+        new MeasurementCollector<List<Pair<PartialPath, String[]>>>(
+            root, pathPattern, limit, offset) {
+          @Override
+          protected void collectMeasurement(IMeasurementMNode node) throws MetadataException {
+            IMeasurementSchema measurementSchema = node.getSchema();
+            String[] tsRow = new String[7];
+            tsRow[0] = node.getAlias();
+            tsRow[1] = getBelongedStorageGroupPath(node).getFullPath();
+            tsRow[2] = measurementSchema.getType().toString();
+            tsRow[3] = measurementSchema.getEncodingType().toString();
+            tsRow[4] = measurementSchema.getCompressor().toString();
+            tsRow[5] = String.valueOf(node.getOffset());
+            tsRow[6] = needLast ? String.valueOf(getLastTimeStamp(node, queryContext)) : null;
+            Pair<PartialPath, String[]> temp = new Pair<>(node.getPartialPath(), tsRow);
+            result.add(temp);
+          }
+        };
     collector.traverse();
-    return collector.getResult();
+    return result;
+  }
+
+  private PartialPath getBelongedStorageGroupPath(IMeasurementMNode node)
+      throws StorageGroupNotSetException {
+    if (node == null) {
+      return null;
+    }
+    IMNode temp = node;
+    while (temp != null) {
+      if (temp.isStorageGroup()) {
+        break;
+      }
+      temp = temp.getParent();
+    }
+    if (temp == null) {
+      throw new StorageGroupNotSetException(node.getFullPath());
+    }
+    return temp.getPartialPath();
   }
 
   public Map<PartialPath, IMeasurementSchema> getAllMeasurementSchemaByPrefix(
@@ -1114,17 +1159,6 @@ public class MTree implements Serializable {
   }
 
   /**
-   * Get the count of timeseries component matching the given path.
-   *
-   * @param pathPattern a path pattern or a full path, may contain wildcard
-   */
-  public int getAllTimeseriesFlatCount(PartialPath pathPattern) throws MetadataException {
-    CounterTraverser counter = new FlatMeasurementCounter(root, pathPattern);
-    counter.traverse();
-    return counter.getCount();
-  }
-
-  /**
    * Get the count of devices matching the given path.
    *
    * @param pathPattern a path pattern or a full path, may contain wildcard
@@ -1173,8 +1207,7 @@ public class MTree implements Serializable {
 
     for (int i = 1; i < nodes.length; i++) {
       if (cur.isMeasurement()) {
-        if (i == nodes.length - 1
-            || cur.getAsMeasurementMNode().getSchema() instanceof VectorMeasurementSchema) {
+        if (i == nodes.length - 1) {
           return cur;
         } else {
           throw new PathNotExistException(path.getFullPath(), true);
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/PathGrouperByStorageGroup.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/PathGrouperByStorageGroup.java
deleted file mode 100644
index 917d1da..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/PathGrouperByStorageGroup.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mtree.traverser;
-
-import org.apache.iotdb.db.conf.IoTDBConstant;
-import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.mnode.IMNode;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.apache.iotdb.db.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
-
-/**
- * This class implements the storage group resolution function as following description.
- *
- * <p>For a path, infer all storage groups it may belong to. The path can have wildcards. Resolve
- * the path or path pattern into StorageGroupName-FullPath pairs that FullPath matches the given
- * path.
- *
- * <p>Consider the path into two parts: (1) the sub path which can not contain a storage group name
- * and (2) the sub path which is substring that begin after the storage group name.
- *
- * <p>(1) Suppose the part of the path can not contain a storage group name (e.g.,
- * "root".contains("root.sg") == false), then: For each one level wildcard *, only one level will be
- * inferred and the wildcard will be removed. For each multi level wildcard **, then the inference
- * will go on until the storage groups are found and the wildcard will be kept. (2) Suppose the part
- * of the path is a substring that begin after the storage group name. (e.g., For
- * "root.*.sg1.a.*.b.*" and "root.x.sg1" is a storage group, then this part is "a.*.b.*"). For this
- * part, keep what it is.
- *
- * <p>Assuming we have three SGs: root.group1, root.group2, root.area1.group3 Eg1: for input
- * "root.**", returns ("root.group1", "root.group1.**"), ("root.group2", "root.group2.**")
- * ("root.area1.group3", "root.area1.group3.**") Eg2: for input "root.*.s1", returns ("root.group1",
- * "root.group1.s1"), ("root.group2", "root.group2.s1")
- *
- * <p>Eg3: for input "root.area1.**", returns ("root.area1.group3", "root.area1.group3.**")
- *
- * <p>ResultSet: StorageGroupName-FullPath pairs
- */
-public class PathGrouperByStorageGroup extends Traverser {
-
-  private Map<String, String> resultSet = new HashMap<>();
-
-  public PathGrouperByStorageGroup(IMNode startNode, PartialPath path) throws MetadataException {
-    super(startNode, path);
-  }
-
-  @Override
-  protected boolean processInternalMatchedMNode(IMNode node, int idx, int level) {
-    if (node.isStorageGroup()) {
-      transferToResult(node, idx);
-      return true;
-    }
-    return false;
-  }
-
-  @Override
-  protected boolean processFullMatchedMNode(IMNode node, int idx, int level) {
-    if (node.isStorageGroup()) {
-      transferToResult(node, idx);
-      return true;
-    }
-    return false;
-  }
-
-  protected void transferToResult(IMNode node, int idx) {
-    // we have found one storage group, record it
-    String sgName = node.getFullPath();
-    // concat the remaining path with the storage group name
-    StringBuilder pathWithKnownSG = new StringBuilder(sgName);
-    for (int i = idx + 1; i < nodes.length; i++) {
-      pathWithKnownSG.append(IoTDBConstant.PATH_SEPARATOR).append(nodes[i]);
-    }
-    if (idx >= nodes.length - 1 && nodes[nodes.length - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
-      // the we find the sg match the last node and the last node is a wildcard (find "root
-      // .group1", for "root.**"), also append the wildcard (to make "root.group1.**")
-      pathWithKnownSG.append(IoTDBConstant.PATH_SEPARATOR).append(MULTI_LEVEL_PATH_WILDCARD);
-    }
-    resultSet.put(sgName, pathWithKnownSG.toString());
-  }
-
-  public Map<String, String> getResult() {
-    return resultSet;
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/BelongedEntityPathCollector.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/BelongedEntityPathCollector.java
deleted file mode 100644
index 265454a..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/BelongedEntityPathCollector.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mtree.traverser.collector;
-
-import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.mnode.IMNode;
-import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
-
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.regex.Pattern;
-
-import static org.apache.iotdb.db.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
-
-// This class implements measurement belonged entity paths collection for given timeseries path
-// pattern.
-// All the entities, that one of the timeseries matching the path pattern belongs to, will be
-// collected.
-public class BelongedEntityPathCollector extends CollectorTraverser<Set<PartialPath>> {
-
-  public BelongedEntityPathCollector(IMNode startNode, PartialPath path) throws MetadataException {
-    super(startNode, path);
-    this.resultSet = new TreeSet<>();
-  }
-
-  @Override
-  protected boolean processInternalMatchedMNode(IMNode node, int idx, int level) {
-    if (!node.isMeasurement() || idx != nodes.length - 2) {
-      return false;
-    }
-    IMeasurementMNode measurementMNode = node.getAsMeasurementMNode();
-    if (measurementMNode.isMultiMeasurement()) {
-      List<String> measurements =
-          measurementMNode.getAsMultiMeasurementMNode().getSubMeasurementList();
-      String regex = nodes[idx + 1].replace("*", ".*");
-      for (String measurement : measurements) {
-        if (!Pattern.matches(regex, measurement)) {
-          resultSet.add(node.getParent().getPartialPath());
-          break;
-        }
-      }
-    }
-    return true;
-  }
-
-  @Override
-  protected boolean processFullMatchedMNode(IMNode node, int idx, int level) {
-    if (!node.isMeasurement()) {
-      return false;
-    }
-    IMeasurementMNode measurementMNode = node.getAsMeasurementMNode();
-    if (measurementMNode.isUnaryMeasurement()) {
-      resultSet.add(node.getParent().getPartialPath());
-    } else if (measurementMNode.isMultiMeasurement()) {
-      if (idx >= nodes.length - 1
-          && !nodes[nodes.length - 1].equals(MULTI_LEVEL_PATH_WILDCARD)
-          && !isPrefixMatch) {
-        return true;
-      }
-      // only when idx > nodes.length or nodes ends with ** or isPrefixMatch
-      resultSet.add(node.getParent().getPartialPath());
-    }
-    return true;
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityPathCollector.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityCollector.java
similarity index 71%
rename from server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityPathCollector.java
rename to server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityCollector.java
index 9c6b29c..1adf684 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityPathCollector.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/EntityCollector.java
@@ -20,26 +20,19 @@ package org.apache.iotdb.db.metadata.mtree.traverser.collector;
 
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.metadata.mnode.IEntityMNode;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 
-import java.util.Set;
-import java.util.TreeSet;
+// This class defines EntityMNode as target node and defines the Entity process framework.
+public abstract class EntityCollector<T> extends CollectorTraverser<T> {
 
-// This class implements the EntityMNode path collection function.
-// Compared with BelongedEntityPathCollector, this class only process entities that full match the
-// path
-// pattern.
-public class EntityPathCollector extends CollectorTraverser<Set<PartialPath>> {
-
-  public EntityPathCollector(IMNode startNode, PartialPath path) throws MetadataException {
+  public EntityCollector(IMNode startNode, PartialPath path) throws MetadataException {
     super(startNode, path);
-    this.resultSet = new TreeSet<>();
   }
 
-  public EntityPathCollector(IMNode startNode, PartialPath path, int limit, int offset)
+  public EntityCollector(IMNode startNode, PartialPath path, int limit, int offset)
       throws MetadataException {
     super(startNode, path, limit, offset);
-    this.resultSet = new TreeSet<>();
   }
 
   @Override
@@ -48,7 +41,8 @@ public class EntityPathCollector extends CollectorTraverser<Set<PartialPath>> {
   }
 
   @Override
-  protected boolean processFullMatchedMNode(IMNode node, int idx, int level) {
+  protected boolean processFullMatchedMNode(IMNode node, int idx, int level)
+      throws MetadataException {
     if (node.isEntity()) {
       if (hasLimit) {
         curOffset += 1;
@@ -56,11 +50,13 @@ public class EntityPathCollector extends CollectorTraverser<Set<PartialPath>> {
           return true;
         }
       }
-      resultSet.add(node.getPartialPath());
+      collectEntity(node.getAsEntityMNode());
       if (hasLimit) {
         count += 1;
       }
     }
     return false;
   }
+
+  protected abstract void collectEntity(IEntityMNode node) throws MetadataException;
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementCollector.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementCollector.java
deleted file mode 100644
index 6760dcc..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementCollector.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mtree.traverser.collector;
-
-import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.mnode.IMNode;
-import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.MultiMeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.UnaryMeasurementMNode;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-import static org.apache.iotdb.db.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
-
-// This class defines MeasurementMNode as target node and
-// defines the measurement component process framework.
-// UnaryMeasurement and each component of MultiMeasurement will be processed.
-public abstract class FlatMeasurementCollector<T> extends CollectorTraverser<T> {
-
-  public FlatMeasurementCollector(IMNode startNode, PartialPath path) throws MetadataException {
-    super(startNode, path);
-    isMeasurementTraverser = true;
-  }
-
-  public FlatMeasurementCollector(IMNode startNode, PartialPath path, int limit, int offset)
-      throws MetadataException {
-    super(startNode, path, limit, offset);
-    isMeasurementTraverser = true;
-  }
-
-  @Override
-  protected boolean processInternalMatchedMNode(IMNode node, int idx, int level)
-      throws MetadataException {
-    if (!node.isMeasurement() || idx != nodes.length - 2) {
-      return false;
-    }
-    IMeasurementMNode measurementMNode = node.getAsMeasurementMNode();
-    if (measurementMNode.isMultiMeasurement()) {
-      MultiMeasurementMNode multiMeasurementMNode = measurementMNode.getAsMultiMeasurementMNode();
-      List<String> measurements = multiMeasurementMNode.getSubMeasurementList();
-      String targetNameRegex = nodes[idx + 1].replace("*", ".*");
-      for (int i = 0; i < measurements.size(); i++) {
-        if (!Pattern.matches(targetNameRegex, measurements.get(i))) {
-          continue;
-        }
-        if (hasLimit) {
-          curOffset += 1;
-          if (curOffset < offset) {
-            break;
-          }
-        }
-        collectMultiMeasurementComponent(multiMeasurementMNode, i);
-        if (hasLimit) {
-          count += 1;
-        }
-      }
-    }
-    return true;
-  }
-
-  @Override
-  protected boolean processFullMatchedMNode(IMNode node, int idx, int level)
-      throws MetadataException {
-    if (!node.isMeasurement()) {
-      return false;
-    }
-    IMeasurementMNode measurementMNode = node.getAsMeasurementMNode();
-    if (measurementMNode.isUnaryMeasurement()) {
-      if (hasLimit) {
-        curOffset += 1;
-        if (curOffset < offset) {
-          return true;
-        }
-      }
-      collectUnaryMeasurement(measurementMNode.getAsUnaryMeasurementMNode());
-      if (hasLimit) {
-        count += 1;
-      }
-    } else if (measurementMNode.isMultiMeasurement()) {
-      if (idx >= nodes.length - 1
-          && !nodes[nodes.length - 1].equals(MULTI_LEVEL_PATH_WILDCARD)
-          && !isPrefixMatch) {
-        return true;
-      }
-      MultiMeasurementMNode multiMeasurementMNode = measurementMNode.getAsMultiMeasurementMNode();
-      // only when idx > nodes.length or nodes ends with ** or isPrefixMatch
-      List<String> measurements = multiMeasurementMNode.getSubMeasurementList();
-      for (int i = 0; i < measurements.size(); i++) {
-        if (hasLimit) {
-          curOffset += 1;
-          if (curOffset < offset) {
-            return true;
-          }
-        }
-        collectMultiMeasurementComponent(multiMeasurementMNode, i);
-        if (hasLimit) {
-          count += 1;
-        }
-      }
-    }
-    return true;
-  }
-
-  /**
-   * collect the information of unary measurement
-   *
-   * @param node MeasurementMNode holding the unary measurement schema
-   */
-  protected abstract void collectUnaryMeasurement(UnaryMeasurementMNode node)
-      throws MetadataException;
-
-  /**
-   * collect the information of target sub measurement of vector measurement
-   *
-   * @param node MeasurementMNode holding the vector measurement schema
-   * @param index the index of target sub measurement
-   */
-  protected abstract void collectMultiMeasurementComponent(MultiMeasurementMNode node, int index)
-      throws MetadataException;
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementPathCollector.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementPathCollector.java
deleted file mode 100644
index 7ca2411..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementPathCollector.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mtree.traverser.collector;
-
-import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.VectorPartialPath;
-import org.apache.iotdb.db.metadata.mnode.IMNode;
-import org.apache.iotdb.db.metadata.mnode.MultiMeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.UnaryMeasurementMNode;
-
-import java.util.LinkedList;
-import java.util.List;
-
-// This class implements the measurement path collection function.
-public class FlatMeasurementPathCollector extends FlatMeasurementCollector<List<PartialPath>> {
-
-  public FlatMeasurementPathCollector(IMNode startNode, PartialPath path) throws MetadataException {
-    super(startNode, path);
-  }
-
-  public FlatMeasurementPathCollector(IMNode startNode, PartialPath path, int limit, int offset)
-      throws MetadataException {
-    super(startNode, path, limit, offset);
-    this.resultSet = new LinkedList<>();
-  }
-
-  @Override
-  protected void collectUnaryMeasurement(UnaryMeasurementMNode node) throws MetadataException {
-    PartialPath path = node.getPartialPath();
-    if (nodes[nodes.length - 1].equals(node.getAlias())) {
-      // only when user query with alias, the alias in path will be set
-      path.setMeasurementAlias(node.getAlias());
-    }
-    resultSet.add(path);
-  }
-
-  @Override
-  protected void collectMultiMeasurementComponent(MultiMeasurementMNode node, int index)
-      throws MetadataException {
-    resultSet.add(
-        new VectorPartialPath(node.getFullPath(), node.getSubMeasurementList().get(index)));
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementSchemaCollector.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementSchemaCollector.java
deleted file mode 100644
index f237691..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/FlatMeasurementSchemaCollector.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mtree.traverser.collector;
-
-import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.VectorPartialPath;
-import org.apache.iotdb.db.metadata.mnode.IMNode;
-import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.MultiMeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.UnaryMeasurementMNode;
-import org.apache.iotdb.db.query.context.QueryContext;
-import org.apache.iotdb.tsfile.utils.Pair;
-import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import static org.apache.iotdb.db.metadata.lastCache.LastCacheManager.getLastTimeStamp;
-
-// This class implements the measurement collection function.
-public class FlatMeasurementSchemaCollector
-    extends FlatMeasurementCollector<List<Pair<PartialPath, String[]>>> {
-
-  // whether show timeseries with last value
-  protected boolean needLast = false;
-  // queryContext helps get last value
-  protected QueryContext queryContext;
-
-  public FlatMeasurementSchemaCollector(IMNode startNode, PartialPath path)
-      throws MetadataException {
-    super(startNode, path);
-    this.resultSet = new LinkedList<>();
-  }
-
-  public FlatMeasurementSchemaCollector(IMNode startNode, PartialPath path, int limit, int offset)
-      throws MetadataException {
-    super(startNode, path, limit, offset);
-    this.resultSet = new LinkedList<>();
-  }
-
-  public void setNeedLast(boolean needLast) {
-    this.needLast = needLast;
-  }
-
-  public void setQueryContext(QueryContext queryContext) {
-    this.queryContext = queryContext;
-  }
-
-  @Override
-  protected void collectUnaryMeasurement(UnaryMeasurementMNode node) throws MetadataException {
-    IMeasurementSchema measurementSchema = node.getSchema();
-    String[] tsRow = new String[7];
-    tsRow[0] = node.getAlias();
-    tsRow[1] = getStorageGroupPath(node).getFullPath();
-    tsRow[2] = measurementSchema.getType().toString();
-    tsRow[3] = measurementSchema.getEncodingType().toString();
-    tsRow[4] = measurementSchema.getCompressor().toString();
-    tsRow[5] = String.valueOf(node.getOffset());
-    tsRow[6] = needLast ? String.valueOf(getLastTimeStamp(node, queryContext)) : null;
-    Pair<PartialPath, String[]> temp = new Pair<>(node.getPartialPath(), tsRow);
-    resultSet.add(temp);
-  }
-
-  @Override
-  protected void collectMultiMeasurementComponent(MultiMeasurementMNode node, int index)
-      throws MetadataException {
-    IMeasurementSchema schema = node.getSchema();
-    List<String> measurements = schema.getSubMeasurementsList();
-    String[] tsRow = new String[7];
-    tsRow[0] = null;
-    tsRow[1] = getStorageGroupPath(node).getFullPath();
-    tsRow[2] = schema.getSubMeasurementsTSDataTypeList().get(index).toString();
-    tsRow[3] = schema.getSubMeasurementsTSEncodingList().get(index).toString();
-    tsRow[4] = schema.getCompressor().toString();
-    tsRow[5] = "-1";
-    tsRow[6] = needLast ? String.valueOf(getLastTimeStamp(node, queryContext)) : null;
-    Pair<PartialPath, String[]> temp =
-        new Pair<>(new VectorPartialPath(node.getFullPath(), measurements.get(index)), tsRow);
-    resultSet.add(temp);
-  }
-
-  private PartialPath getStorageGroupPath(IMeasurementMNode node)
-      throws StorageGroupNotSetException {
-    if (node == null) {
-      return null;
-    }
-    IMNode temp = node;
-    while (temp != null) {
-      if (temp.isStorageGroup()) {
-        break;
-      }
-      temp = temp.getParent();
-    }
-    if (temp == null) {
-      throw new StorageGroupNotSetException(node.getFullPath());
-    }
-    return temp.getPartialPath();
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MeasurementCollector.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MeasurementCollector.java
index 4c504ae..61f5534 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MeasurementCollector.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/MeasurementCollector.java
@@ -23,9 +23,7 @@ import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
 import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
 
-// This class defines MeasurementMNode as target node
-// and defines the measurement process framework.
-// MultiMeasurement will be processed as one unit.
+// This class defines MeasurementMNode as target node and defines the measurement process framework.
 public abstract class MeasurementCollector<T> extends CollectorTraverser<T> {
 
   public MeasurementCollector(IMNode startNode, PartialPath path) throws MetadataException {
@@ -33,6 +31,12 @@ public abstract class MeasurementCollector<T> extends CollectorTraverser<T> {
     isMeasurementTraverser = true;
   }
 
+  public MeasurementCollector(IMNode startNode, PartialPath path, int limit, int offset)
+      throws MetadataException {
+    super(startNode, path, limit, offset);
+    isMeasurementTraverser = true;
+  }
+
   @Override
   protected boolean processInternalMatchedMNode(IMNode node, int idx, int level)
       throws MetadataException {
@@ -45,7 +49,16 @@ public abstract class MeasurementCollector<T> extends CollectorTraverser<T> {
     if (!node.isMeasurement()) {
       return false;
     }
+    if (hasLimit) {
+      curOffset += 1;
+      if (curOffset < offset) {
+        return true;
+      }
+    }
     collectMeasurement(node.getAsMeasurementMNode());
+    if (hasLimit) {
+      count += 1;
+    }
     return true;
   }
 
@@ -54,5 +67,5 @@ public abstract class MeasurementCollector<T> extends CollectorTraverser<T> {
    *
    * @param node MeasurementMNode holding the measurement schema
    */
-  protected abstract void collectMeasurement(IMeasurementMNode node);
+  protected abstract void collectMeasurement(IMeasurementMNode node) throws MetadataException;
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupPathCollector.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupCollector.java
similarity index 79%
rename from server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupPathCollector.java
rename to server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupCollector.java
index f9eef82..40aa55c 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupPathCollector.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/collector/StorageGroupCollector.java
@@ -21,25 +21,22 @@ package org.apache.iotdb.db.metadata.mtree.traverser.collector;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
 import org.apache.iotdb.db.metadata.PartialPath;
 import org.apache.iotdb.db.metadata.mnode.IMNode;
-
-import java.util.LinkedList;
-import java.util.List;
+import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 
 // This class implements storage group path collection function.
-public class StorageGroupPathCollector extends CollectorTraverser<List<PartialPath>> {
+public abstract class StorageGroupCollector<T> extends CollectorTraverser<T> {
 
   protected boolean collectInternal = false;
 
-  public StorageGroupPathCollector(IMNode startNode, PartialPath path) throws MetadataException {
+  public StorageGroupCollector(IMNode startNode, PartialPath path) throws MetadataException {
     super(startNode, path);
-    this.resultSet = new LinkedList<>();
   }
 
   @Override
   protected boolean processInternalMatchedMNode(IMNode node, int idx, int level) {
     if (node.isStorageGroup()) {
       if (collectInternal) {
-        transferToResult(node);
+        collectStorageGroup(node.getAsStorageGroupMNode());
       }
       return true;
     }
@@ -49,15 +46,13 @@ public class StorageGroupPathCollector extends CollectorTraverser<List<PartialPa
   @Override
   protected boolean processFullMatchedMNode(IMNode node, int idx, int level) {
     if (node.isStorageGroup()) {
-      transferToResult(node);
+      collectStorageGroup(node.getAsStorageGroupMNode());
       return true;
     }
     return false;
   }
 
-  private void transferToResult(IMNode node) {
-    resultSet.add(node.getPartialPath());
-  }
+  protected abstract void collectStorageGroup(IStorageGroupMNode node);
 
   public void setCollectInternal(boolean collectInternal) {
     this.collectInternal = collectInternal;
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/FlatMeasurementCounter.java b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/FlatMeasurementCounter.java
deleted file mode 100644
index e9297e6..0000000
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/traverser/counter/FlatMeasurementCounter.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.iotdb.db.metadata.mtree.traverser.counter;
-
-import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.mnode.IMNode;
-import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-import static org.apache.iotdb.db.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
-
-// This method implements the measurement component count function.
-// Each component of MultiMeasurement will be count once.
-// E.g. given MTree: root.sg.d.s, root.sg.d.vector[s1, s2]; FlatMeasurementCount will be 3.
-public class FlatMeasurementCounter extends CounterTraverser {
-  public FlatMeasurementCounter(IMNode startNode, PartialPath path) throws MetadataException {
-    super(startNode, path);
-    isMeasurementTraverser = true;
-  }
-
-  @Override
-  protected boolean processInternalMatchedMNode(IMNode node, int idx, int level)
-      throws MetadataException {
-    if (!node.isMeasurement() || idx != nodes.length - 2) {
-      return false;
-    }
-    IMeasurementMNode measurementMNode = node.getAsMeasurementMNode();
-    if (measurementMNode.isMultiMeasurement()) {
-      List<String> measurements =
-          measurementMNode.getAsMultiMeasurementMNode().getSubMeasurementList();
-      String regex = nodes[idx + 1].replace("*", ".*");
-      for (String measurement : measurements) {
-        if (Pattern.matches(regex, measurement)) {
-          count++;
-        }
-      }
-    }
-    return true;
-  }
-
-  @Override
-  protected boolean processFullMatchedMNode(IMNode node, int idx, int level)
-      throws MetadataException {
-    if (!node.isMeasurement()) {
-      return false;
-    }
-    IMeasurementMNode measurementMNode = node.getAsMeasurementMNode();
-    if (measurementMNode.isUnaryMeasurement()) {
-      count++;
-    } else if (measurementMNode.isMultiMeasurement()) {
-      if (idx >= nodes.length - 1 && !nodes[nodes.length - 1].equals(MULTI_LEVEL_PATH_WILDCARD)) {
-        return true;
-      }
-      // only when idx > nodes.length or nodes ends with **
-      count += measurementMNode.getMeasurementCount();
-    }
-    return true;
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java b/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java
index 9017f98..b967abf 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java
@@ -18,24 +18,14 @@
  */
 package org.apache.iotdb.db.metadata.template;
 
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
-import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
 import org.apache.iotdb.db.qp.physical.crud.CreateTemplatePlan;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.schema.UnaryMeasurementSchema;
-import org.apache.iotdb.tsfile.write.schema.VectorMeasurementSchema;
 
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 public class Template {
   private String name;
@@ -52,37 +42,12 @@ public class Template {
 
     // put measurement into a map
     for (int i = 0; i < plan.getMeasurements().size(); i++) {
-      IMeasurementSchema curSchema;
-      // vector
-      int size = plan.getMeasurements().get(i).size();
-      if (size > 1) {
-        String[] measurementsArray = new String[size];
-        TSDataType[] typeArray = new TSDataType[size];
-        TSEncoding[] encodingArray = new TSEncoding[size];
-
-        for (int j = 0; j < size; j++) {
-          measurementsArray[j] = plan.getMeasurements().get(i).get(j);
-          typeArray[j] = plan.getDataTypes().get(i).get(j);
-          encodingArray[j] = plan.getEncodings().get(i).get(j);
-        }
-
-        curSchema =
-            new VectorMeasurementSchema(
-                plan.getSchemaNames().get(i),
-                measurementsArray,
-                typeArray,
-                encodingArray,
-                plan.getCompressors().get(i));
-      }
-      // normal measurement
-      else {
-        curSchema =
-            new UnaryMeasurementSchema(
-                plan.getMeasurements().get(i).get(0),
-                plan.getDataTypes().get(i).get(0),
-                plan.getEncodings().get(i).get(0),
-                plan.getCompressors().get(i));
-      }
+      IMeasurementSchema curSchema =
+          new UnaryMeasurementSchema(
+              plan.getSchemaNames().get(i),
+              plan.getDataTypes().get(i).get(0),
+              plan.getEncodings().get(i).get(0),
+              plan.getCompressors().get(i));
 
       String path = plan.getSchemaNames().get(i);
       if (schemaMap.containsKey(path)) {
@@ -110,71 +75,12 @@ public class Template {
     this.schemaMap = schemaMap;
   }
 
-  /**
-   * check whether a timeseries path is compatible with this template
-   *
-   * @param path timeseries path
-   * @return whether we can create this new timeseries (whether it's compatible with this template)
-   */
-  public boolean isCompatible(PartialPath path) {
-    return !(schemaMap.containsKey(path.getMeasurement())
-        || schemaMap.containsKey(path.getDevicePath().getMeasurement()));
-  }
-
   public boolean hasSchema(String measurementId) {
     return schemaMap.containsKey(measurementId);
   }
 
-  public List<IMeasurementMNode> getMeasurementMNode() {
-    Set<IMeasurementSchema> deduplicateSchema = new HashSet<>();
-    List<IMeasurementMNode> res = new ArrayList<>();
-
-    for (IMeasurementSchema measurementSchema : schemaMap.values()) {
-      if (deduplicateSchema.add(measurementSchema)) {
-        IMeasurementMNode measurementMNode = null;
-        if (measurementSchema instanceof UnaryMeasurementSchema) {
-          measurementMNode =
-              MeasurementMNode.getMeasurementMNode(
-                  null, measurementSchema.getMeasurementId(), measurementSchema, null);
-
-        } else if (measurementSchema instanceof VectorMeasurementSchema) {
-          measurementMNode =
-              MeasurementMNode.getMeasurementMNode(
-                  null,
-                  getMeasurementNodeName(measurementSchema.getMeasurementId()),
-                  measurementSchema,
-                  null);
-        }
-
-        res.add(measurementMNode);
-      }
-    }
-
-    return res;
-  }
-
-  public String getMeasurementNodeName(String measurementName) {
-    return schemaMap.get(measurementName).getMeasurementId();
-  }
-
-  /**
-   * get all path in this template (to support aligned by device query)
-   *
-   * @return a hash map looks like below {vector -> [s1, s2, s3] normal_timeseries -> []}
-   */
-  public HashMap<String, List<String>> getAllPath() {
-    HashMap<String, List<String>> res = new HashMap<>();
-    for (Map.Entry<String, IMeasurementSchema> schemaEntry : schemaMap.entrySet()) {
-      if (schemaEntry.getValue() instanceof VectorMeasurementSchema) {
-        VectorMeasurementSchema vectorMeasurementSchema =
-            (VectorMeasurementSchema) schemaEntry.getValue();
-        res.put(schemaEntry.getKey(), vectorMeasurementSchema.getSubMeasurementsList());
-      } else {
-        res.put(schemaEntry.getKey(), new ArrayList<>());
-      }
-    }
-
-    return res;
+  public IMeasurementSchema getSchema(String measurementId) {
+    return schemaMap.get(measurementId);
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
index fe4c59f..5327b64 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
@@ -721,7 +721,7 @@ public class PlanExecutor implements IPlanExecutor {
   }
 
   protected List<PartialPath> getPathsName(PartialPath path) throws MetadataException {
-    return IoTDB.metaManager.getFlatMeasurementPaths(path);
+    return IoTDB.metaManager.getMeasurementPaths(path);
   }
 
   protected List<PartialPath> getNodesList(PartialPath schemaPattern, int level)
@@ -1217,8 +1217,7 @@ public class PlanExecutor implements IPlanExecutor {
         }
       }
       for (PartialPath path :
-          IoTDB.metaManager.getFlatMeasurementPaths(
-              devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD))) {
+          IoTDB.metaManager.getMeasurementPaths(devicePath.concatNode(ONE_LEVEL_PATH_WILDCARD))) {
         existSeriesSet.add(path.getMeasurement());
         existSeriesSet.add(path.getMeasurementAlias());
       }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
index 8ad429f..bcec94d 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
@@ -501,7 +501,7 @@ public class QueryOperator extends Operator {
   }
 
   protected List<PartialPath> getMatchedTimeseries(PartialPath path) throws MetadataException {
-    return IoTDB.metaManager.getFlatMeasurementPaths(path);
+    return IoTDB.metaManager.getMeasurementPaths(path);
   }
 
   public boolean isEnableTracing() {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
index 4031a5c..882ff29 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java
@@ -238,7 +238,7 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
     try {
       for (PartialPath originalPath : originalPaths) {
         List<PartialPath> all =
-            IoTDB.metaManager.getFlatMeasurementPathsWithAlias(originalPath, 0, 0).left;
+            IoTDB.metaManager.getMeasurementPathsWithAlias(originalPath, 0, 0).left;
         if (all.isEmpty()) {
           throw new LogicalOptimizeException(
               String.format("Unknown time series %s in `where clause`", originalPath));
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java b/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
index 3fbc71c..d91cc6c 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
@@ -59,7 +59,7 @@ public class WildcardsRemover {
   public List<PartialPath> removeWildcardFrom(PartialPath path) throws LogicalOptimizeException {
     try {
       Pair<List<PartialPath>, Integer> pair =
-          IoTDB.metaManager.getFlatMeasurementPathsWithAlias(path, currentLimit, currentOffset);
+          IoTDB.metaManager.getMeasurementPathsWithAlias(path, currentLimit, currentOffset);
 
       consumed += pair.right;
       if (currentOffset != 0) {
diff --git a/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
index 03bea3b..ae06254 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
@@ -264,7 +264,11 @@ public class LastQueryExecutor {
     private IMeasurementMNode node;
 
     LastCacheAccessor(PartialPath seriesPath) {
-      this.path = seriesPath;
+      if (seriesPath instanceof VectorPartialPath) {
+        this.path = seriesPath.concatNode(((VectorPartialPath) seriesPath).getSubSensor(0));
+      } else {
+        this.path = seriesPath;
+      }
     }
 
     public TimeValuePair read() {
@@ -283,33 +287,14 @@ public class LastQueryExecutor {
         return null;
       }
 
-      if (path instanceof VectorPartialPath) {
-        // the seriesPath has been transformed to vector path
-        // here needs subSensor path
-        return IoTDB.metaManager.getLastCache(
-            node.getAsMultiMeasurementMNode(), ((VectorPartialPath) path).getSubSensor(0));
-      } else {
-        return IoTDB.metaManager.getLastCache(node.getAsUnaryMeasurementMNode());
-      }
+      return IoTDB.metaManager.getLastCache(node);
     }
 
     public void write(TimeValuePair pair) {
       if (node == null) {
         IoTDB.metaManager.updateLastCache(path, pair, false, Long.MIN_VALUE);
       } else {
-        if (path instanceof VectorPartialPath) {
-          // the seriesPath has been transformed to vector path
-          // here needs subSensor path
-          IoTDB.metaManager.updateLastCache(
-              node.getAsMultiMeasurementMNode(),
-              ((VectorPartialPath) path).getSubSensor(0),
-              pair,
-              false,
-              Long.MIN_VALUE);
-        } else {
-          IoTDB.metaManager.updateLastCache(
-              node.getAsUnaryMeasurementMNode(), pair, false, Long.MIN_VALUE);
-        }
+        IoTDB.metaManager.updateLastCache(node, pair, false, Long.MIN_VALUE);
       }
     }
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
index 6a8cc7e..c1bba28 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
@@ -389,7 +389,7 @@ public class TSServiceImpl implements TSIService.Iface {
   }
 
   protected List<PartialPath> getPaths(PartialPath path) throws MetadataException {
-    return IoTDB.metaManager.getFlatMeasurementPaths(path);
+    return IoTDB.metaManager.getMeasurementPaths(path);
   }
 
   private boolean executeInsertRowsPlan(InsertRowsPlan insertRowsPlan, List<TSStatus> result) {
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
index 7c133d8..319a0c9 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerAdvancedTest.java
@@ -151,17 +151,17 @@ public class MManagerAdvancedTest {
           new PartialPath("root.vehicle.d0"),
           mmanager.getBelongedStorageGroup(new PartialPath("root.vehicle.d0.s1")));
       List<PartialPath> pathList =
-          mmanager.getFlatMeasurementPaths(new PartialPath("root.vehicle.d1.**"));
+          mmanager.getMeasurementPaths(new PartialPath("root.vehicle.d1.**"));
       assertEquals(6, pathList.size());
-      pathList = mmanager.getFlatMeasurementPaths(new PartialPath("root.vehicle.d0.**"));
+      pathList = mmanager.getMeasurementPaths(new PartialPath("root.vehicle.d0.**"));
       assertEquals(6, pathList.size());
-      pathList = mmanager.getFlatMeasurementPaths(new PartialPath("root.vehicle.d*.**"));
+      pathList = mmanager.getMeasurementPaths(new PartialPath("root.vehicle.d*.**"));
       assertEquals(12, pathList.size());
-      pathList = mmanager.getFlatMeasurementPaths(new PartialPath("root.ve*.**"));
+      pathList = mmanager.getMeasurementPaths(new PartialPath("root.ve*.**"));
       assertEquals(12, pathList.size());
-      pathList = mmanager.getFlatMeasurementPaths(new PartialPath("root.vehicle*.d*.s1"));
+      pathList = mmanager.getMeasurementPaths(new PartialPath("root.vehicle*.d*.s1"));
       assertEquals(2, pathList.size());
-      pathList = mmanager.getFlatMeasurementPaths(new PartialPath("root.vehicle.d2.**"));
+      pathList = mmanager.getMeasurementPaths(new PartialPath("root.vehicle.d2.**"));
       assertEquals(0, pathList.size());
     } catch (MetadataException e) {
       e.printStackTrace();
@@ -217,14 +217,10 @@ public class MManagerAdvancedTest {
     TimeValuePair tv3 = new TimeValuePair(1500, TsPrimitiveType.getByType(TSDataType.DOUBLE, 2.5));
     PartialPath path = new PartialPath("root.vehicle.d2.s0");
     IMeasurementMNode node = mmanager.getMeasurementMNode(path);
-    LastCacheManager.updateLastCache(path, tv1, true, Long.MIN_VALUE, node);
-    LastCacheManager.updateLastCache(path, tv2, true, Long.MIN_VALUE, node);
-    Assert.assertEquals(
-        tv2.getTimestamp(),
-        mmanager.getLastCache(node.getAsUnaryMeasurementMNode()).getTimestamp());
-    LastCacheManager.updateLastCache(path, tv3, true, Long.MIN_VALUE, node);
-    Assert.assertEquals(
-        tv2.getTimestamp(),
-        mmanager.getLastCache(node.getAsUnaryMeasurementMNode()).getTimestamp());
+    LastCacheManager.updateLastCache(node, tv1, true, Long.MIN_VALUE);
+    LastCacheManager.updateLastCache(node, tv2, true, Long.MIN_VALUE);
+    Assert.assertEquals(tv2.getTimestamp(), mmanager.getLastCache(node).getTimestamp());
+    LastCacheManager.updateLastCache(node, tv3, true, Long.MIN_VALUE);
+    Assert.assertEquals(tv2.getTimestamp(), mmanager.getLastCache(node).getTimestamp());
   }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
index d694c90..7256f42 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
@@ -287,23 +287,7 @@ public class MManagerBasicTest {
     assertTrue(manager.isPathExist(new PartialPath("root.laptop.d1.vector.s2")));
     assertTrue(manager.isPathExist(new PartialPath("root.laptop.d1.vector.s3")));
 
-    try {
-      manager.deleteTimeseries(new PartialPath("root.laptop.d1.vector.s2"));
-    } catch (MetadataException e) {
-      assertEquals(
-          e.getMessage(),
-          "No matched timeseries or aligned timeseries for Path [root.laptop.d1.vector.s2]");
-    }
-
-    try {
-      manager.deleteTimeseries(new PartialPath("root.laptop.d1.vector.*"));
-    } catch (MetadataException e) {
-      assertEquals(
-          e.getMessage(),
-          "No matched timeseries or aligned timeseries for Path [root.laptop.d1.vector.*]");
-    }
-
-    manager.deleteTimeseries(new PartialPath("root.laptop.d1.vector"));
+    manager.deleteTimeseries(new PartialPath("root.laptop.d1.vector.*"));
     assertTrue(manager.isPathExist(new PartialPath("root.laptop.d1")));
     assertTrue(manager.isPathExist(new PartialPath("root.laptop.d1.s0")));
     assertFalse(manager.isPathExist(new PartialPath("root.laptop.d1.vector")));
@@ -546,7 +530,7 @@ public class MManagerBasicTest {
     MManager manager = IoTDB.metaManager;
 
     try {
-      assertTrue(manager.getFlatMeasurementPaths(new PartialPath("root")).isEmpty());
+      assertTrue(manager.getMeasurementPaths(new PartialPath("root")).isEmpty());
       assertTrue(manager.getBelongedStorageGroups(new PartialPath("root")).isEmpty());
       assertTrue(manager.getBelongedStorageGroups(new PartialPath("root.vehicle")).isEmpty());
       assertTrue(
@@ -930,7 +914,7 @@ public class MManagerBasicTest {
     encodingList.add(encodings);
 
     List<CompressionType> compressionTypes = new ArrayList<>();
-    for (int i = 0; i < 11; i++) {
+    for (int i = 0; i < 2; i++) {
       compressionTypes.add(CompressionType.SNAPPY);
     }
 
@@ -1035,7 +1019,7 @@ public class MManagerBasicTest {
 
     CreateTimeSeriesPlan createTimeSeriesPlan2 =
         new CreateTimeSeriesPlan(
-            new PartialPath("root.sg1.d1.vector.s1"),
+            new PartialPath("root.sg1.d1.vector"),
             TSDataType.INT32,
             TSEncoding.PLAIN,
             CompressionType.GZIP,
@@ -1049,7 +1033,7 @@ public class MManagerBasicTest {
       fail();
     } catch (Exception e) {
       assertEquals(
-          "Path [root.sg1.d1.vector.s1 ( which is incompatible with template )] already exist",
+          "Path [root.sg1.d1.vector ( which is incompatible with template )] already exist",
           e.getMessage());
     }
   }
@@ -1229,16 +1213,6 @@ public class MManagerBasicTest {
           TSEncoding.valueOf("RLE"),
           compressionType,
           Collections.emptyMap());
-      manager.createAlignedTimeSeries(
-          new PartialPath("root.laptop.d1.vector"),
-          Arrays.asList("s1", "s2", "s3"),
-          Arrays.asList(
-              TSDataType.valueOf("INT32"),
-              TSDataType.valueOf("FLOAT"),
-              TSDataType.valueOf("INT32")),
-          Arrays.asList(
-              TSEncoding.valueOf("RLE"), TSEncoding.valueOf("RLE"), TSEncoding.valueOf("RLE")),
-          compressionType);
 
       // show timeseries root.laptop.d1.s0
       ShowTimeSeriesPlan showTimeSeriesPlan =
@@ -1248,75 +1222,25 @@ public class MManagerBasicTest {
           manager.showTimeseries(showTimeSeriesPlan, EnvironmentUtils.TEST_QUERY_CONTEXT);
       assertEquals(1, result.size());
       assertEquals("root.laptop.d1.s0", result.get(0).getName());
-
-      // show timeseries
-      //      showTimeSeriesPlan =
-      //          new ShowTimeSeriesPlan(new PartialPath("root"), false, null, null, 0, 0, false);
-      //      result = manager.showTimeseries(showTimeSeriesPlan,
-      // EnvironmentUtils.TEST_QUERY_CONTEXT);
-      //      assertEquals(4, result.size());
-
-      // show timeseries root.laptop.d1.vector
-      showTimeSeriesPlan =
-          new ShowTimeSeriesPlan(
-              new PartialPath("root.laptop.d1.vector.*"), false, null, null, 0, 0, false);
-      result = manager.showTimeseries(showTimeSeriesPlan, EnvironmentUtils.TEST_QUERY_CONTEXT);
-      assertEquals(3, result.size());
-      for (int i = 0; i < result.size(); i++) {
-        assertEquals("root.laptop.d1.vector.s" + (i + 1), result.get(i).getName());
-      }
-
-      // show timeseries root.laptop.d1.vector.s1
-      showTimeSeriesPlan =
-          new ShowTimeSeriesPlan(
-              new PartialPath("root.laptop.d1.vector.s1"), false, null, null, 0, 0, false);
-      result = manager.showTimeseries(showTimeSeriesPlan, EnvironmentUtils.TEST_QUERY_CONTEXT);
-      assertEquals(1, result.size());
-      assertEquals("root.laptop.d1.vector.s1", result.get(0).getName());
     } catch (MetadataException e) {
       e.printStackTrace();
       fail(e.getMessage());
     }
-
-    // show timeseries root.laptop.d1.(s0,s1)
-    try {
-      ShowTimeSeriesPlan showTimeSeriesPlan =
-          new ShowTimeSeriesPlan(
-              new PartialPath("root.laptop.d1.(s0,s1)"), false, null, null, 0, 0, false);
-      List<ShowTimeSeriesResult> result =
-          manager.showTimeseries(showTimeSeriesPlan, EnvironmentUtils.TEST_QUERY_CONTEXT);
-    } catch (MetadataException e) {
-      assertEquals(
-          "Cannot get node of children in different aligned timeseries (Path: (s0,s1))",
-          e.getMessage());
-    }
   }
 
   @Test
   public void testShowTimeseriesWithTemplate() {
     List<List<String>> measurementList = new ArrayList<>();
     measurementList.add(Collections.singletonList("s0"));
-    List<String> measurements = new ArrayList<>();
-    for (int i = 1; i <= 3; i++) {
-      measurements.add("s" + i);
-    }
-    measurementList.add(measurements);
+    measurementList.add(Collections.singletonList("s1"));
 
     List<List<TSDataType>> dataTypeList = new ArrayList<>();
     dataTypeList.add(Collections.singletonList(TSDataType.INT32));
-    List<TSDataType> dataTypes = new ArrayList<>();
-    dataTypes.add(TSDataType.INT32);
-    dataTypes.add(TSDataType.FLOAT);
-    dataTypes.add(TSDataType.INT32);
-    dataTypeList.add(dataTypes);
+    dataTypeList.add(Collections.singletonList(TSDataType.INT32));
 
     List<List<TSEncoding>> encodingList = new ArrayList<>();
     encodingList.add(Collections.singletonList(TSEncoding.RLE));
-    List<TSEncoding> encodings = new ArrayList<>();
-    for (int i = 1; i <= 3; i++) {
-      encodings.add(TSEncoding.RLE);
-    }
-    encodingList.add(encodings);
+    encodingList.add(Collections.singletonList(TSEncoding.RLE));
 
     List<CompressionType> compressionTypes = new ArrayList<>();
     for (int i = 0; i < 2; i++) {
@@ -1325,7 +1249,7 @@ public class MManagerBasicTest {
 
     List<String> schemaNames = new ArrayList<>();
     schemaNames.add("s0");
-    schemaNames.add("vector");
+    schemaNames.add("s1");
 
     CreateTemplatePlan plan =
         new CreateTemplatePlan(
@@ -1354,27 +1278,17 @@ public class MManagerBasicTest {
       assertEquals(1, result.size());
       assertEquals("root.laptop.d1.s0", result.get(0).getName());
 
-      // show timeseries root.laptop.d1.vector.s1
-      showTimeSeriesPlan =
-          new ShowTimeSeriesPlan(
-              new PartialPath("root.laptop.d1.vector.s1"), false, null, null, 0, 0, false);
-      result = manager.showTimeseries(showTimeSeriesPlan, EnvironmentUtils.TEST_QUERY_CONTEXT);
-      assertEquals(1, result.size());
-      assertEquals("root.laptop.d1.vector.s1", result.get(0).getName());
-
       // show timeseries root.laptop.d1.(s1,s2,s3)
       showTimeSeriesPlan =
           new ShowTimeSeriesPlan(new PartialPath("root.**"), false, null, null, 0, 0, false);
       result = manager.showTimeseries(showTimeSeriesPlan, EnvironmentUtils.TEST_QUERY_CONTEXT);
-      assertEquals(4, result.size());
+      assertEquals(2, result.size());
       Set<String> set = new HashSet<>();
-      for (int i = 1; i < result.size(); i++) {
-        set.add("root.laptop.d1.vector.s" + i);
-      }
       set.add("root.laptop.d1.s0");
+      set.add("root.laptop.d1.s1");
 
-      for (int i = 0; i < result.size(); i++) {
-        set.remove(result.get(i).getName());
+      for (ShowTimeSeriesResult showTimeSeriesResult : result) {
+        set.remove(showTimeSeriesResult.getName());
       }
 
       assertTrue(set.isEmpty());
@@ -1656,8 +1570,7 @@ public class MManagerBasicTest {
 
       // call getSeriesSchemasAndReadLockDevice
       IMNode node = manager.getSeriesSchemasAndReadLockDevice(insertRowPlan);
-      assertEquals(1, manager.getAllTimeseriesCount(node.getPartialPath().concatNode("**")));
-      assertEquals(3, manager.getAllTimeseriesFlatCount(node.getPartialPath().concatNode("**")));
+      assertEquals(3, manager.getAllTimeseriesCount(node.getPartialPath().concatNode("**")));
       assertNull(insertRowPlan.getMeasurementMNodes()[0]);
       assertNull(insertRowPlan.getMeasurementMNodes()[1]);
       assertNull(insertRowPlan.getMeasurementMNodes()[2]);
@@ -1711,7 +1624,7 @@ public class MManagerBasicTest {
     } catch (Exception e) {
       e.printStackTrace();
       Assert.assertEquals(
-          "Path [root.laptop.d1.vector] is an aligned timeseries, please set InsertPlan.isAligned() = true",
+          "Timeseries under path [root.laptop.d1.vector] is aligned , please set InsertPlan.isAligned() = true",
           e.getMessage());
     }
   }
@@ -1795,7 +1708,7 @@ public class MManagerBasicTest {
     } catch (Exception e) {
       e.printStackTrace();
       Assert.assertEquals(
-          "Path [root.laptop.d1.vector] is not an aligned timeseries, please set InsertPlan.isAligned() = false",
+          "Timeseries under path [root.laptop.d1.vector] is not aligned , please set InsertPlan.isAligned() = false",
           e.getMessage());
     }
   }
diff --git a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
index 51f1ff3..0cff3d1 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MTreeTest.java
@@ -148,7 +148,7 @@ public class MTreeTest {
           Collections.emptyMap(),
           null);
     } catch (MetadataException e) {
-      Assert.assertEquals(String.format("%s is not a legal path", "aa.bb.cc"), e.getMessage());
+      Assert.assertEquals(String.format("%s is not a legal path", "aa.bb"), e.getMessage());
     }
   }
 
@@ -206,12 +206,12 @@ public class MTreeTest {
     }
 
     try {
-      List<PartialPath> result = root.getFlatMeasurementPaths(new PartialPath("root.a.*.s0"));
+      List<PartialPath> result = root.getMeasurementPaths(new PartialPath("root.a.*.s0"));
       assertEquals(2, result.size());
       assertEquals("root.a.d0.s0", result.get(0).getFullPath());
       assertEquals("root.a.d1.s0", result.get(1).getFullPath());
 
-      result = root.getFlatMeasurementPaths(new PartialPath("root.a.*.*.s0"));
+      result = root.getMeasurementPaths(new PartialPath("root.a.*.*.s0"));
       assertEquals("root.a.b.d0.s0", result.get(0).getFullPath());
     } catch (MetadataException e) {
       e.printStackTrace();
@@ -273,18 +273,18 @@ public class MTreeTest {
     }
 
     try {
-      List<PartialPath> result = root.getFlatMeasurementPaths(new PartialPath("root.a.*.s0"));
+      List<PartialPath> result = root.getMeasurementPaths(new PartialPath("root.a.*.s0"));
       assertEquals(2, result.size());
       assertEquals("root.a.d0.s0", result.get(0).getFullPath());
       assertEquals("root.a.d1.s0", result.get(1).getFullPath());
 
-      result = root.getFlatMeasurementPaths(new PartialPath("root.a.*.temperature"));
+      result = root.getMeasurementPaths(new PartialPath("root.a.*.temperature"));
       assertEquals(2, result.size());
       assertEquals("root.a.d0.s0", result.get(0).getFullPath());
       assertEquals("root.a.d1.s0", result.get(1).getFullPath());
 
       List<PartialPath> result2 =
-          root.getFlatMeasurementPathsWithAlias(new PartialPath("root.a.*.s0"), 0, 0).left;
+          root.getMeasurementPathsWithAlias(new PartialPath("root.a.*.s0"), 0, 0).left;
       assertEquals(2, result2.size());
       assertEquals("root.a.d0.s0", result2.get(0).getFullPath());
       assertFalse(result2.get(0).isMeasurementAliasExists());
@@ -292,13 +292,13 @@ public class MTreeTest {
       assertFalse(result2.get(1).isMeasurementAliasExists());
 
       result2 =
-          root.getFlatMeasurementPathsWithAlias(new PartialPath("root.a.*.temperature"), 0, 0).left;
+          root.getMeasurementPathsWithAlias(new PartialPath("root.a.*.temperature"), 0, 0).left;
       assertEquals(2, result2.size());
       assertEquals("root.a.d0.temperature", result2.get(0).getFullPathWithAlias());
       assertEquals("root.a.d1.temperature", result2.get(1).getFullPathWithAlias());
 
       Pair<List<PartialPath>, Integer> result3 =
-          root.getFlatMeasurementPathsWithAlias(new PartialPath("root.a.**"), 2, 0);
+          root.getMeasurementPathsWithAlias(new PartialPath("root.a.**"), 2, 0);
       assertEquals(2, result3.left.size());
       assertEquals(2, result3.right.intValue());
 
@@ -724,9 +724,9 @@ public class MTreeTest {
     assertEquals(2, root.getDevices(new PartialPath("root"), true).size());
     assertEquals(2, root.getDevices(new PartialPath("root.**"), false).size());
     assertEquals(2, root.getAllTimeseriesCount(new PartialPath("root.**")));
-    assertEquals(2, root.getFlatMeasurementPaths(new PartialPath("root.**")).size());
+    assertEquals(2, root.getMeasurementPaths(new PartialPath("root.**")).size());
     assertEquals(
-        2, root.getFlatMeasurementPathsWithAlias(new PartialPath("root.**"), 0, 0).left.size());
+        2, root.getMeasurementPathsWithAlias(new PartialPath("root.**"), 0, 0).left.size());
   }
 
   @Test