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

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


The following commit(s) were added to refs/heads/dev/1.3 by this push:
     new b17a2c9c2e3 [To dev/1.3] Fix aggregation query when device cross 
region in TreeModel #16650
b17a2c9c2e3 is described below

commit b17a2c9c2e396581e67125574ebd82770d5c275b
Author: Weihao Li <[email protected]>
AuthorDate: Fri Oct 24 17:48:50 2025 +0800

    [To dev/1.3] Fix aggregation query when device cross region in TreeModel 
#16650
---
 .../partition/IoTDBPartitionShuffleStrategyIT.java |  4 +-
 .../db/it/alignbydevice/IoTDBAlignByDevice2IT.java |  8 ++-
 .../db/it/alignbydevice/IoTDBAlignByDevice3IT.java |  8 ++-
 ...ByDevice2IT.java => IoTDBAlignByDevice4IT.java} | 17 +++--
 .../db/it/alignbydevice/IoTDBAlignByDeviceIT.java  | 34 +++++-----
 .../IoTDBAlignByDeviceWithTemplate2IT.java         |  8 ++-
 ...java => IoTDBAlignByDeviceWithTemplate3IT.java} | 21 +++---
 ...DBAlignByDeviceWithTemplateAggregation2IT.java} | 23 ++++---
 ...oTDBAlignByDeviceWithTemplateAggregationIT.java |  4 +-
 .../IoTDBAlignByDeviceWithTemplateIT.java          | 11 ++--
 .../IoTDBOrderByLimitOffsetAlignByDevice2IT.java   |  8 ++-
 ...> IoTDBOrderByLimitOffsetAlignByDevice3IT.java} | 17 +++--
 .../IoTDBOrderByLimitOffsetAlignByDeviceIT.java    |  4 +-
 .../IoTDBOrderByWithAlignByDevice2IT.java          |  8 ++-
 .../IoTDBOrderByWithAlignByDevice3IT.java          |  8 ++-
 ....java => IoTDBOrderByWithAlignByDevice4IT.java} | 19 ++++--
 .../IoTDBOrderByWithAlignByDeviceIT.java           |  4 +-
 .../db/it/alignbydevice/IoTDBShuffleSink1IT.java   |  8 +--
 ...ByDevice2IT.java => IoTDBShuffleSink1_2IT.java} | 27 +++++---
 .../db/it/alignbydevice/IoTDBShuffleSink2IT.java   | 10 +--
 ...ByDevice2IT.java => IoTDBShuffleSink2_2IT.java} | 29 +++++----
 .../db/queryengine/plan/analyze/TemplatedInfo.java |  6 +-
 .../expression/visitor/ConcatDeviceVisitor.java    | 27 +++-----
 .../plan/planner/OperatorTreeGenerator.java        | 36 +++++++----
 .../plan/planner/distribution/SourceRewriter.java  | 74 ++++++++++++++++------
 .../planner/plan/node/process/AggregationNode.java |  2 +-
 .../plan/node/process/RawDataAggregationNode.java  |  2 +-
 .../node/source/SeriesAggregationSourceNode.java   |  4 +-
 28 files changed, 273 insertions(+), 158 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/confignode/it/partition/IoTDBPartitionShuffleStrategyIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/confignode/it/partition/IoTDBPartitionShuffleStrategyIT.java
index 70f170caa11..1294c911d6b 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/confignode/it/partition/IoTDBPartitionShuffleStrategyIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/confignode/it/partition/IoTDBPartitionShuffleStrategyIT.java
@@ -53,7 +53,7 @@ public class IoTDBPartitionShuffleStrategyIT {
   private static final String testDataRegionConsensusProtocolClass =
       ConsensusFactory.RATIS_CONSENSUS;
   private static final int testReplicationFactor = 1;
-  private static final String testDataPartitionAllocationStrategy = "SHUFFLE";
+  public static final String SHUFFLE = "SHUFFLE";
   private static final int testSeriesSlotNum = 1000;
   private static final long testTimePartitionInterval = 604800000;
   private static final double testDataRegionPerDataNode = 5.0;
@@ -70,7 +70,7 @@ public class IoTDBPartitionShuffleStrategyIT {
         .setDataReplicationFactor(testReplicationFactor)
         .setTimePartitionInterval(testTimePartitionInterval)
         .setSeriesSlotNum(testSeriesSlotNum)
-        
.setDataPartitionAllocationStrategy(testDataPartitionAllocationStrategy)
+        .setDataPartitionAllocationStrategy(SHUFFLE)
         .setDataRegionPerDataNode(testDataRegionPerDataNode);
 
     // Init 1C1D environment
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
index efca7a3f540..c1418f9359c 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
@@ -20,21 +20,25 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBAlignByDevice2IT extends IoTDBAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     
EnvFactory.getEnv().getConfig().getCommonConfig().setDegreeOfParallelism(4);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice3IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice3IT.java
index 68b2c40cc6b..5171bad3d23 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice3IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice3IT.java
@@ -20,24 +20,28 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
 /**
  * Change series_slot_num to 1, to generate more devices which are cross data 
regions as possible.
  */
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBAlignByDevice3IT extends IoTDBAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice4IT.java
similarity index 58%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
copy to 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice4IT.java
index efca7a3f540..3b8f269f8ca 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice4IT.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -20,21 +20,28 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
-public class IoTDBAlignByDevice2IT extends IoTDBAlignByDeviceIT {
+import static 
org.apache.iotdb.confignode.it.partition.IoTDBPartitionShuffleStrategyIT.SHUFFLE;
 
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBAlignByDevice4IT extends IoTDBAlignByDeviceIT {
   @BeforeClass
-  public static void setUp() throws Exception {
-    
EnvFactory.getEnv().getConfig().getCommonConfig().setDegreeOfParallelism(4);
+  public static void setUp() {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(1024 * 
1024);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setTimePartitionInterval(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataPartitionAllocationStrategy(SHUFFLE);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceIT.java
index 1bb3e76061d..bf82d7a9950 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceIT.java
@@ -104,13 +104,13 @@ public class IoTDBAlignByDeviceIT {
       };
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
@@ -662,27 +662,29 @@ public class IoTDBAlignByDeviceIT {
   @Test
   public void aggregateTest() {
     String[] retArray =
-        new String[] {"root.vehicle.d0,11,11,6,6,1,", 
"root.vehicle.d1,2,null,null,null,null,"};
+        new String[] {
+          "root.vehicle.d0,11,55555,1000.11,good,true,", 
"root.vehicle.d1,2,null,null,null,null,"
+        };
 
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
 
       try (ResultSet resultSet =
           statement.executeQuery(
-              "select count(s0),count(s1),count(s2),count(s3),count(s4) "
+              "select 
count(s0),max_value(s1),max_value(s2),last_value(s3),last_value(s4) "
                   + "from root.vehicle.d1,root.vehicle.d0 align by device")) {
         ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
         List<Integer> actualIndexToExpectedIndexList =
             checkHeader(
                 resultSetMetaData,
-                "Device,count(s0),count(s1),count(s2),count(s3),count(s4)",
+                
"Device,count(s0),max_value(s1),max_value(s2),last_value(s3),last_value(s4)",
                 new int[] {
                   Types.VARCHAR,
                   Types.BIGINT,
                   Types.BIGINT,
-                  Types.BIGINT,
-                  Types.BIGINT,
-                  Types.BIGINT,
+                  Types.FLOAT,
+                  Types.VARCHAR,
+                  Types.BOOLEAN,
                 });
 
         int cnt = 0;
@@ -711,9 +713,9 @@ public class IoTDBAlignByDeviceIT {
   public void groupByTimeTest() {
     String[] retArray =
         new String[] {
-          "2,root.vehicle.d0,1,1,3,0,0,",
-          "22,root.vehicle.d0,0,0,0,0,0,",
-          "42,root.vehicle.d0,0,0,0,0,0,",
+          "2,root.vehicle.d0,1,40000,4.44,null,null,",
+          "22,root.vehicle.d0,0,null,null,null,null,",
+          "42,root.vehicle.d0,0,null,null,null,null,",
           "2,root.vehicle.d1,0,null,null,null,null,",
           "22,root.vehicle.d1,0,null,null,null,null,",
           "42,root.vehicle.d1,0,null,null,null,null,"
@@ -724,20 +726,20 @@ public class IoTDBAlignByDeviceIT {
 
       try (ResultSet resultSet =
           statement.executeQuery(
-              "select count(*) from root.vehicle.** GROUP BY ([2,50),20ms) 
align by device")) {
+              "select 
count(s0),max_value(s1),max_value(s2),last_value(s3),last_value(s4) from 
root.vehicle.** GROUP BY ([2,50),20ms) align by device")) {
         ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
         List<Integer> actualIndexToExpectedIndexList =
             checkHeader(
                 resultSetMetaData,
-                
"Time,Device,count(s0),count(s1),count(s2),count(s3),count(s4)",
+                
"Time,Device,count(s0),max_value(s1),max_value(s2),last_value(s3),last_value(s4)",
                 new int[] {
                   Types.TIMESTAMP,
                   Types.VARCHAR,
                   Types.BIGINT,
                   Types.BIGINT,
-                  Types.BIGINT,
-                  Types.BIGINT,
-                  Types.BIGINT,
+                  Types.FLOAT,
+                  Types.VARCHAR,
+                  Types.BOOLEAN,
                 });
 
         int cnt = 0;
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate2IT.java
index a4da0898f75..155f6eceeba 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate2IT.java
@@ -20,24 +20,28 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
 /**
  * Change series_slot_num to 1, to generate more devices which are cross data 
regions as possible.
  */
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBAlignByDeviceWithTemplate2IT extends 
IoTDBAlignByDeviceWithTemplateIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate3IT.java
similarity index 59%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate2IT.java
copy to 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate3IT.java
index a4da0898f75..8dfcadb7e1e 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplate3IT.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -20,24 +20,29 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
-/**
- * Change series_slot_num to 1, to generate more devices which are cross data 
regions as possible.
- */
-public class IoTDBAlignByDeviceWithTemplate2IT extends 
IoTDBAlignByDeviceWithTemplateIT {
+import static 
org.apache.iotdb.confignode.it.partition.IoTDBPartitionShuffleStrategyIT.SHUFFLE;
+
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBAlignByDeviceWithTemplate3IT extends 
IoTDBAlignByDeviceWithTemplateIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
-    EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
+  public static void setUp() {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(1024 * 
1024);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setTimePartitionInterval(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataPartitionAllocationStrategy(SHUFFLE);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregation2IT.java
similarity index 56%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
copy to 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregation2IT.java
index 85713e87e5d..e88a6a20419 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregation2IT.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -20,27 +20,30 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
-import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData;
-import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData2;
+import static 
org.apache.iotdb.confignode.it.partition.IoTDBPartitionShuffleStrategyIT.SHUFFLE;
 
-public class IoTDBOrderByLimitOffsetAlignByDevice2IT
-    extends IoTDBOrderByLimitOffsetAlignByDeviceIT {
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBAlignByDeviceWithTemplateAggregation2IT
+    extends IoTDBAlignByDeviceWithTemplateAggregationIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
-    EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
+  public static void setUp() {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(1024 * 
1024);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setTimePartitionInterval(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataPartitionAllocationStrategy(SHUFFLE);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
-    insertData2();
-    insertData3();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
index d8ab1e2c3fc..38f2a961646 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java
@@ -72,13 +72,13 @@ public class IoTDBAlignByDeviceWithTemplateAggregationIT {
       };
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateIT.java
index a71cb773713..82758290dbb 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateIT.java
@@ -63,13 +63,13 @@ public class IoTDBAlignByDeviceWithTemplateIT {
   String[] retArray;
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
@@ -969,13 +969,16 @@ public class IoTDBAlignByDeviceWithTemplateIT {
   public void emptyResultTest() {
     String[] expectedHeader = new String[] {"Time,Device,s3,s1,s2"};
     String[] retArray = new String[] {};
+    // We set timePartitionInterval to 1 in IoTDBAlignByDeviceWithTemplate3IT, 
the where predicate
+    // is changed from 'time>=now()-1d' to 'time>=now()-1ms' to reduce memory 
use because of the
+    // creation of timeslots.
     resultSetEqualTest(
-        "SELECT * FROM root.sg1.** where time>=now()-1d and time<=now() "
+        "SELECT * FROM root.sg1.** where time>=now()-1ms and time<=now() "
             + "ORDER BY TIME DESC ALIGN BY DEVICE;",
         expectedHeader,
         retArray);
     resultSetEqualTest(
-        "SELECT * FROM root.sg2.** where time>=now()-1d and time<=now() "
+        "SELECT * FROM root.sg2.** where time>=now()-1ms and time<=now() "
             + "ORDER BY TIME DESC ALIGN BY DEVICE;",
         expectedHeader,
         retArray);
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
index 85713e87e5d..bf8a37833b0 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
@@ -20,18 +20,22 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
 import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData;
 import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData2;
 
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBOrderByLimitOffsetAlignByDevice2IT
     extends IoTDBOrderByLimitOffsetAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
@@ -40,7 +44,7 @@ public class IoTDBOrderByLimitOffsetAlignByDevice2IT
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice3IT.java
similarity index 64%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
copy to 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice3IT.java
index 85713e87e5d..8b3de311aa8 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice3IT.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -20,19 +20,26 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
+import static 
org.apache.iotdb.confignode.it.partition.IoTDBPartitionShuffleStrategyIT.SHUFFLE;
 import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData;
 import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData2;
 
-public class IoTDBOrderByLimitOffsetAlignByDevice2IT
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBOrderByLimitOffsetAlignByDevice3IT
     extends IoTDBOrderByLimitOffsetAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
-    EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
+  public static void setUp() {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(1024 * 
1024);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setTimePartitionInterval(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataPartitionAllocationStrategy(SHUFFLE);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
     insertData2();
@@ -40,7 +47,7 @@ public class IoTDBOrderByLimitOffsetAlignByDevice2IT
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDeviceIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDeviceIT.java
index 60cf1a5d5f0..99115fdfada 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDeviceIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDeviceIT.java
@@ -41,7 +41,7 @@ import static 
org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
 public class IoTDBOrderByLimitOffsetAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
     insertData2();
@@ -49,7 +49,7 @@ public class IoTDBOrderByLimitOffsetAlignByDeviceIT {
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice2IT.java
index 519f8e76d93..6e6b810d8f2 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice2IT.java
@@ -20,21 +20,25 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBOrderByWithAlignByDevice2IT extends 
IoTDBOrderByWithAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     
EnvFactory.getEnv().getConfig().getCommonConfig().setDegreeOfParallelism(4);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice3IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice3IT.java
index 011972ea471..c5a9fd465c5 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice3IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice3IT.java
@@ -20,21 +20,25 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
+@Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBOrderByWithAlignByDevice3IT extends 
IoTDBOrderByWithAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice4IT.java
similarity index 58%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice2IT.java
copy to 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice4IT.java
index 519f8e76d93..fac649b2a96 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDevice4IT.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -20,21 +20,30 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
-public class IoTDBOrderByWithAlignByDevice2IT extends 
IoTDBOrderByWithAlignByDeviceIT {
+import static 
org.apache.iotdb.confignode.it.partition.IoTDBPartitionShuffleStrategyIT.SHUFFLE;
+
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBOrderByWithAlignByDevice4IT extends 
IoTDBOrderByWithAlignByDeviceIT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
-    
EnvFactory.getEnv().getConfig().getCommonConfig().setDegreeOfParallelism(4);
+  public static void setUp() {
+    EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(1024 * 
1024);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setTimePartitionInterval(timeGap);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataPartitionAllocationStrategy(SHUFFLE);
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
+    insertData2();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDeviceIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDeviceIT.java
index 610c831170e..a8c40bc7ae1 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDeviceIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByWithAlignByDeviceIT.java
@@ -72,14 +72,14 @@ public class IoTDBOrderByWithAlignByDeviceIT {
   public static final Map<String, double[]> deviceToAvgPrecipitation = new 
HashMap<>();
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().initClusterEnvironment();
     insertData();
     insertData2();
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink1IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink1IT.java
index 484fd5d9d94..095783fdd20 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink1IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink1IT.java
@@ -36,7 +36,7 @@ import static 
org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
 @RunWith(IoTDBTestRunner.class)
 @Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBShuffleSink1IT {
-  private static final String[] SINGLE_SERIES =
+  protected static final String[] SINGLE_SERIES =
       new String[] {
         "create database root.single",
         "insert into root.single.d1(time,s1) values (1,2)",
@@ -45,7 +45,7 @@ public class IoTDBShuffleSink1IT {
         "insert into root.single.d2(time,s1) values (now(),5)"
       };
   // two devices
-  private static final String[] MULTI_SERIES =
+  protected static final String[] MULTI_SERIES =
       new String[] {
         "create database root.sg",
         "insert into root.sg.d1(time,s1,s2) values (1,2,2)",
@@ -55,7 +55,7 @@ public class IoTDBShuffleSink1IT {
       };
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
     
EnvFactory.getEnv().getConfig().getCommonConfig().setDataRegionGroupExtensionPolicy("CUSTOM");
     
EnvFactory.getEnv().getConfig().getCommonConfig().setDefaultDataRegionGroupNumPerDatabase(2);
@@ -65,7 +65,7 @@ public class IoTDBShuffleSink1IT {
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink1_2IT.java
similarity index 51%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
copy to 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink1_2IT.java
index 85713e87e5d..58ca0947f17 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink1_2IT.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -20,27 +20,34 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
-import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData;
-import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData2;
+import static 
org.apache.iotdb.confignode.it.partition.IoTDBPartitionShuffleStrategyIT.SHUFFLE;
+import static org.apache.iotdb.db.it.utils.TestUtils.prepareData;
 
-public class IoTDBOrderByLimitOffsetAlignByDevice2IT
-    extends IoTDBOrderByLimitOffsetAlignByDeviceIT {
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBShuffleSink1_2IT extends IoTDBShuffleSink1IT {
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataRegionGroupExtensionPolicy("CUSTOM");
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDefaultDataRegionGroupNumPerDatabase(2);
+    EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(1024 * 
1024);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setTimePartitionInterval(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataPartitionAllocationStrategy(SHUFFLE);
     EnvFactory.getEnv().initClusterEnvironment();
-    insertData();
-    insertData2();
-    insertData3();
+    prepareData(SINGLE_SERIES);
+    prepareData(MULTI_SERIES);
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink2IT.java
index cd29526e956..17368548d85 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink2IT.java
@@ -36,7 +36,7 @@ import static 
org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
 @RunWith(IoTDBTestRunner.class)
 @Category({LocalStandaloneIT.class, ClusterIT.class})
 public class IoTDBShuffleSink2IT {
-  private static final String[] SINGLE_SERIES =
+  protected static final String[] SINGLE_SERIES =
       new String[] {
         "create database root.single",
         "insert into root.single.d1(time,s1) values (1,1)",
@@ -48,7 +48,7 @@ public class IoTDBShuffleSink2IT {
       };
 
   // three devices, three data regions
-  private static final String[] MULTI_SERIES =
+  protected static final String[] MULTI_SERIES =
       new String[] {
         "create database root.sg",
         "insert into root.sg.d1(time,s1,s2) values (1,1,1)",
@@ -60,7 +60,7 @@ public class IoTDBShuffleSink2IT {
       };
 
   // three devices, three data regions, d3 has only one region
-  private static final String[] SECOND_MULTI_SERIES =
+  protected static final String[] SECOND_MULTI_SERIES =
       new String[] {
         "create database root.sg1",
         "insert into root.sg1.d1(time,s1,s2) values (1,1,1)",
@@ -71,7 +71,7 @@ public class IoTDBShuffleSink2IT {
       };
 
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
     
EnvFactory.getEnv().getConfig().getCommonConfig().setDataRegionGroupExtensionPolicy("CUSTOM");
     
EnvFactory.getEnv().getConfig().getCommonConfig().setDefaultDataRegionGroupNumPerDatabase(3);
@@ -82,7 +82,7 @@ public class IoTDBShuffleSink2IT {
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink2_2IT.java
similarity index 50%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
copy to 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink2_2IT.java
index 85713e87e5d..2272e53ec95 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBOrderByLimitOffsetAlignByDevice2IT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBShuffleSink2_2IT.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -20,27 +20,34 @@
 package org.apache.iotdb.db.it.alignbydevice;
 
 import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
+import org.junit.experimental.categories.Category;
 
-import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData;
-import static 
org.apache.iotdb.db.it.alignbydevice.IoTDBOrderByWithAlignByDeviceIT.insertData2;
-
-public class IoTDBOrderByLimitOffsetAlignByDevice2IT
-    extends IoTDBOrderByLimitOffsetAlignByDeviceIT {
+import static 
org.apache.iotdb.confignode.it.partition.IoTDBPartitionShuffleStrategyIT.SHUFFLE;
+import static org.apache.iotdb.db.it.utils.TestUtils.prepareData;
 
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBShuffleSink2_2IT extends IoTDBShuffleSink2IT {
   @BeforeClass
-  public static void setUp() throws Exception {
+  public static void setUp() {
     EnvFactory.getEnv().getConfig().getCommonConfig().setSeriesSlotNum(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataRegionGroupExtensionPolicy("CUSTOM");
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDefaultDataRegionGroupNumPerDatabase(3);
+    EnvFactory.getEnv().getConfig().getCommonConfig().setSortBufferSize(1024 * 
1024);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setTimePartitionInterval(1);
+    
EnvFactory.getEnv().getConfig().getCommonConfig().setDataPartitionAllocationStrategy(SHUFFLE);
     EnvFactory.getEnv().initClusterEnvironment();
-    insertData();
-    insertData2();
-    insertData3();
+    prepareData(SINGLE_SERIES);
+    prepareData(MULTI_SERIES);
+    prepareData(SECOND_MULTI_SERIES);
   }
 
   @AfterClass
-  public static void tearDown() throws Exception {
+  public static void tearDown() {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedInfo.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedInfo.java
index 919efa8970c..8241bf11005 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedInfo.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedInfo.java
@@ -60,7 +60,7 @@ public class TemplatedInfo {
   private final boolean queryAllSensors;
 
   // variables used in DeviceViewOperator
-  private final List<String> deviceViewOutputNames;
+  private List<String> deviceViewOutputNames;
   private List<Integer> deviceToMeasurementIndexes;
 
   // variables related to LIMIT/OFFSET push down
@@ -150,6 +150,10 @@ public class TemplatedInfo {
     return this.deviceViewOutputNames;
   }
 
+  public void setDeviceViewOutputNames(List<String> deviceViewOutputNames) {
+    this.deviceViewOutputNames = deviceViewOutputNames;
+  }
+
   public long getOffsetValue() {
     return this.offsetValue;
   }
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ConcatDeviceVisitor.java
similarity index 56%
copy from 
integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
copy to 
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ConcatDeviceVisitor.java
index efca7a3f540..7099fd63217 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDevice2IT.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/visitor/ConcatDeviceVisitor.java
@@ -7,7 +7,7 @@
  * "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
+ *     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
@@ -17,24 +17,17 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.it.alignbydevice;
+package org.apache.iotdb.db.queryengine.plan.expression.visitor;
 
-import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.queryengine.plan.expression.Expression;
+import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
 
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
+public class ConcatDeviceVisitor extends ReconstructVisitor<String> {
 
-public class IoTDBAlignByDevice2IT extends IoTDBAlignByDeviceIT {
-
-  @BeforeClass
-  public static void setUp() throws Exception {
-    
EnvFactory.getEnv().getConfig().getCommonConfig().setDegreeOfParallelism(4);
-    EnvFactory.getEnv().initClusterEnvironment();
-    insertData();
-  }
-
-  @AfterClass
-  public static void tearDown() throws Exception {
-    EnvFactory.getEnv().cleanClusterEnvironment();
+  @Override
+  public Expression visitTimeSeriesOperand(TimeSeriesOperand 
timeSeriesOperand, String device) {
+    return new TimeSeriesOperand(
+        new PartialPath(device, timeSeriesOperand.getExpressionString(), 
false));
   }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
index 2f1b9671e31..cf34ea8609d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java
@@ -226,6 +226,7 @@ import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.AlignedSeri
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.DeviceRegionScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.LastQueryScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.SeriesAggregationScanNode;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.SeriesAggregationSourceNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.SeriesScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.ShowQueriesNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.TimeseriesRegionScanNode;
@@ -608,7 +609,8 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
       SeriesAggregationScanNode node, LocalExecutionPlanContext context) {
     PartialPath seriesPath = node.getSeriesPath();
     boolean ascending = node.getScanOrder() == ASC;
-    List<AggregationDescriptor> aggregationDescriptors = 
node.getAggregationDescriptorList();
+    List<AggregationDescriptor> aggregationDescriptors =
+        
AggregationNode.getDeduplicatedDescriptors(node.getAggregationDescriptorList());
     List<Aggregator> aggregators = new ArrayList<>();
     aggregationDescriptors.forEach(
         o ->
@@ -629,7 +631,7 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
         initTimeRangeIterator(groupByTimeParameter, ascending, true, 
context.getZoneId());
     long maxReturnSize =
         AggregationUtil.calculateMaxAggregationResultSize(
-            node.getAggregationDescriptorList(), timeRangeIterator, 
context.getTypeProvider());
+            aggregationDescriptors, timeRangeIterator, 
context.getTypeProvider());
 
     SeriesScanOptions.Builder scanOptionsBuilder = 
getSeriesScanOptionsBuilder(context);
     scanOptionsBuilder.withAllSensors(
@@ -681,6 +683,7 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
   @Override
   public Operator visitAlignedSeriesAggregationScan(
       AlignedSeriesAggregationScanNode node, LocalExecutionPlanContext 
context) {
+
     if (context.isBuildPlanUseTemplate()) {
       Ordering scanOrder = context.getTemplatedInfo().getScanOrder();
       if (node.getDescriptorType() == 1) {
@@ -690,7 +693,7 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
       return constructAlignedSeriesAggregationScanOperator(
           node.getPlanNodeId(),
           node.getAlignedPath(),
-          node.getAggregationDescriptorList(),
+          
AggregationNode.getDeduplicatedDescriptors(node.getAggregationDescriptorList()),
           context.getTemplatedInfo().getPushDownPredicate(),
           scanOrder,
           context.getTemplatedInfo().getGroupByTimeParameter(),
@@ -701,7 +704,7 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
     return constructAlignedSeriesAggregationScanOperator(
         node.getPlanNodeId(),
         node.getAlignedPath(),
-        node.getAggregationDescriptorList(),
+        
AggregationNode.getDeduplicatedDescriptors(node.getAggregationDescriptorList()),
         node.getPushDownPredicate(),
         node.getScanOrder(),
         node.getGroupByTimeParameter(),
@@ -1984,8 +1987,9 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
     Operator child = node.getChild().accept(this, context);
     boolean ascending = node.getScanOrder() == ASC;
     List<Aggregator> aggregators = new ArrayList<>();
-    List<AggregationDescriptor> aggregationDescriptors = 
node.getAggregationDescriptorList();
-    for (AggregationDescriptor descriptor : 
node.getAggregationDescriptorList()) {
+    List<AggregationDescriptor> aggregationDescriptors =
+        
AggregationNode.getDeduplicatedDescriptors(node.getAggregationDescriptorList());
+    for (AggregationDescriptor descriptor : aggregationDescriptors) {
       List<InputLocation[]> inputLocationList = 
calcInputLocationList(descriptor, layout);
       aggregators.add(
           new Aggregator(
@@ -2443,7 +2447,7 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
     List<ColumnMerger> mergers = createColumnMergers(outputColumns, 
timeComparator);
     List<TSDataType> outputColumnTypes =
         context.getTypeProvider().getTemplatedInfo() != null
-            ? getOutputColumnTypesOfTimeJoinNode(node)
+            ? getOutputColumnTypesOfTimeJoinNode(node, context)
             : getOutputColumnTypes(node, context.getTypeProvider());
 
     return new FullOuterTimeJoinOperator(
@@ -2471,7 +2475,7 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
         node.getMergeOrder() == ASC ? ASC_TIME_COMPARATOR : 
DESC_TIME_COMPARATOR;
     List<TSDataType> outputColumnTypes =
         context.getTypeProvider().getTemplatedInfo() != null
-            ? getOutputColumnTypesOfTimeJoinNode(node)
+            ? getOutputColumnTypesOfTimeJoinNode(node, context)
             : getOutputColumnTypes(node, context.getTypeProvider());
 
     return new InnerTimeJoinOperator(
@@ -2525,7 +2529,7 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
         node.getMergeOrder() == ASC ? ASC_TIME_COMPARATOR : 
DESC_TIME_COMPARATOR;
     List<TSDataType> outputColumnTypes =
         context.getTypeProvider().getTemplatedInfo() != null
-            ? getOutputColumnTypesOfTimeJoinNode(node)
+            ? getOutputColumnTypesOfTimeJoinNode(node, context)
             : getOutputColumnTypes(node, context.getTypeProvider());
 
     return new LeftOuterTimeJoinOperator(
@@ -3211,7 +3215,8 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
         .collect(Collectors.toList());
   }
 
-  private List<TSDataType> getOutputColumnTypesOfTimeJoinNode(PlanNode node) {
+  private List<TSDataType> getOutputColumnTypesOfTimeJoinNode(
+      PlanNode node, LocalExecutionPlanContext context) {
     // Only templated device situation can invoke this method,
     // the children of TimeJoinNode can only be ScanNode or TimeJoinNode
     List<TSDataType> dataTypes = new ArrayList<>();
@@ -3223,11 +3228,14 @@ public class OperatorTreeGenerator extends 
PlanVisitor<Operator, LocalExecutionP
       } else if (child instanceof FullOuterTimeJoinNode
           || child instanceof InnerTimeJoinNode
           || child instanceof LeftOuterTimeJoinNode) {
-        dataTypes.addAll(getOutputColumnTypesOfTimeJoinNode(child));
+        dataTypes.addAll(getOutputColumnTypesOfTimeJoinNode(child, context));
+      } else if (child instanceof SeriesAggregationSourceNode) {
+        dataTypes.addAll(getOutputColumnTypes(child, 
context.getTypeProvider()));
       } else {
-        LOGGER.error(
-            "Unexpected PlanNode in getOutputColumnTypesOfTimeJoinNode, type: 
{}",
-            child.getOutputColumnNames());
+        throw new UnsupportedOperationException(
+            String.format(
+                "Unexpected PlanNode in getOutputColumnTypesOfTimeJoinNode, 
type: %s",
+                child.getOutputColumnNames()));
       }
     }
     return dataTypes;
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
index 354ba952822..32647d29457 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/SourceRewriter.java
@@ -32,10 +32,11 @@ import org.apache.iotdb.commons.utils.TimePartitionUtils;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.execution.MemoryEstimationHelper;
 import org.apache.iotdb.db.queryengine.plan.analyze.Analysis;
+import org.apache.iotdb.db.queryengine.plan.analyze.TemplatedInfo;
 import org.apache.iotdb.db.queryengine.plan.expression.Expression;
-import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand;
 import 
org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression;
 import org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionType;
+import 
org.apache.iotdb.db.queryengine.plan.expression.visitor.ConcatDeviceVisitor;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.BaseSourceRewriter;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
@@ -103,7 +104,6 @@ import java.util.Set;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 
-import static com.google.common.base.Preconditions.checkArgument;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.LAST_VALUE;
 import static 
org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
 import static org.apache.iotdb.commons.partition.DataPartition.NOT_ASSIGNED;
@@ -291,12 +291,28 @@ public class SourceRewriter extends 
BaseSourceRewriter<DistributionPlanContext>
                 : Collections.singletonList(newIdxSum++));
       }
 
+      boolean useTemplate = node.getDeviceToMeasurementIndexesMap() == null;
+      TemplatedInfo templatedInfo = 
context.queryContext.getTypeProvider().getTemplatedInfo();
       for (String device : node.getDevices()) {
-        List<Integer> oldMeasurementIdxList = 
node.getDeviceToMeasurementIndexesMap().get(device);
+        List<Integer> oldMeasurementIdxList =
+            useTemplate
+                ? context
+                    .queryContext
+                    .getTypeProvider()
+                    .getTemplatedInfo()
+                    .getDeviceToMeasurementIndexes()
+                : node.getDeviceToMeasurementIndexesMap().get(device);
         List<Integer> newMeasurementIdxList = new ArrayList<>();
         oldMeasurementIdxList.forEach(
             idx -> 
newMeasurementIdxList.addAll(newMeasurementIdxMap.get(idx)));
-        node.getDeviceToMeasurementIndexesMap().put(device, 
newMeasurementIdxList);
+
+        if (useTemplate) {
+          templatedInfo.setDeviceToMeasurementIndexes(newMeasurementIdxList);
+          templatedInfo.setDeviceViewOutputNames(newPartialOutputColumns);
+          break;
+        } else {
+          node.getDeviceToMeasurementIndexesMap().put(device, 
newMeasurementIdxList);
+        }
       }
 
       for (PlanNode planNode : deviceViewNodeList) {
@@ -306,12 +322,20 @@ public class SourceRewriter extends 
BaseSourceRewriter<DistributionPlanContext>
 
         List<String> devices = deviceViewNode.getDevices();
         for (int j = 0; j < devices.size(); j++) {
-          if (deviceViewNode.getChildren().get(j) instanceof ProjectNode) {
-            String device = devices.get(j);
+          boolean childIsProject = deviceViewNode.getChildren().get(j) 
instanceof ProjectNode;
+          String device = devices.get(j);
+          List<Integer> newMeasurementIdxList =
+              useTemplate
+                  ? templatedInfo.getDeviceToMeasurementIndexes()
+                  : 
deviceViewNode.getDeviceToMeasurementIndexesMap().get(device);
+          // If child is ProjectNode, we need to set new outputs;
+          // If child is not ProjectNode and input columns size of 
deviceViewNode is larger than
+          // child output columns size, we need to construct a ProjectNode.
+          if (childIsProject
+              || newMeasurementIdxList.size()
+                  > 
deviceViewNode.getChildren().get(j).getOutputColumnNames().size()) {
 
             // construct output column names for each child ProjectNode
-            List<Integer> newMeasurementIdxList =
-                deviceViewNode.getDeviceToMeasurementIndexesMap().get(device);
             List<String> newProjectOutputs =
                 newMeasurementIdxList.stream()
                     .map(
@@ -320,19 +344,33 @@ public class SourceRewriter extends 
BaseSourceRewriter<DistributionPlanContext>
                           FunctionExpression aggExpression =
                               actualPartialAggregations.get(measurementIdx);
 
-                          // construct new FunctionExpression with device for 
ProjectNode
-                          List<Expression> withDeviceExpressions =
-                              getWithDeviceExpressions(aggExpression, device);
+                          List<Expression> inputs;
+                          if (!useTemplate) {
+                            // construct new FunctionExpression with device 
for ProjectNode
+                            inputs = getWithDeviceExpressions(aggExpression, 
device.toString());
+                          } else {
+                            // when use Template, the outputs of 
SeriesAggregationScanNode are
+                            // without device, so the ProjectNode needn't 
concat device
+                            inputs = aggExpression.getExpressions();
+                          }
                           aggExpression =
                               new FunctionExpression(
                                   aggExpression.getFunctionName(),
                                   aggExpression.getFunctionAttributes(),
-                                  withDeviceExpressions);
+                                  inputs);
                           return aggExpression.getExpressionString();
                         })
                     .collect(Collectors.toList());
-            ((ProjectNode) deviceViewNode.getChildren().get(j))
-                .setOutputColumnNames(newProjectOutputs);
+            if (childIsProject) {
+              ((ProjectNode) deviceViewNode.getChildren().get(j))
+                  .setOutputColumnNames(newProjectOutputs);
+            } else {
+              ProjectNode projectNode =
+                  new ProjectNode(
+                      context.queryContext.getQueryId().genPlanNodeId(), 
newProjectOutputs);
+              projectNode.setChild(deviceViewNode.getChildren().get(j));
+              deviceViewNode.getChildren().set(j, projectNode);
+            }
           }
         }
       }
@@ -371,16 +409,12 @@ public class SourceRewriter extends 
BaseSourceRewriter<DistributionPlanContext>
   }
 
   private static List<Expression> getWithDeviceExpressions(
-      FunctionExpression aggExpression, String device) {
+      Expression aggExpression, String device) {
     return aggExpression.getExpressions().stream()
         .map(
             // process each argument of FunctionExpression
             argument -> {
-              checkArgument(
-                  argument instanceof TimeSeriesOperand,
-                  "Argument of AggregationFunction should be TimeSeriesOperand 
here");
-              return new TimeSeriesOperand(
-                  new PartialPath(device, argument.getExpressionString(), 
false));
+              return new ConcatDeviceVisitor().process(argument, device);
             })
         .collect(Collectors.toList());
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/AggregationNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/AggregationNode.java
index b7e1aea74f1..83411d62678 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/AggregationNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/AggregationNode.java
@@ -194,7 +194,7 @@ public class AggregationNode extends MultiChildProcessNode {
       outputColumnNames.add(ColumnHeaderConstant.ENDTIME);
     }
     outputColumnNames.addAll(
-        aggregationDescriptorList.stream()
+        getDeduplicatedDescriptors(aggregationDescriptorList).stream()
             .map(AggregationDescriptor::getOutputColumnNames)
             .flatMap(List::stream)
             .collect(Collectors.toList()));
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/RawDataAggregationNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/RawDataAggregationNode.java
index 24a207184e0..066de467c14 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/RawDataAggregationNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/process/RawDataAggregationNode.java
@@ -200,7 +200,7 @@ public class RawDataAggregationNode extends 
SingleChildProcessNode {
       outputColumnNames.add(ColumnHeaderConstant.ENDTIME);
     }
     outputColumnNames.addAll(
-        aggregationDescriptorList.stream()
+        
AggregationNode.getDeduplicatedDescriptors(aggregationDescriptorList).stream()
             .map(AggregationDescriptor::getOutputColumnNames)
             .flatMap(List::stream)
             .collect(Collectors.toList()));
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/SeriesAggregationSourceNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/SeriesAggregationSourceNode.java
index 791122583f9..b24584e8523 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/SeriesAggregationSourceNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/SeriesAggregationSourceNode.java
@@ -34,6 +34,8 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
+import static 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.AggregationNode.getDeduplicatedDescriptors;
+
 public abstract class SeriesAggregationSourceNode extends SeriesSourceNode {
 
   // The list of aggregate functions, each AggregateDescriptor will be output 
as one column in
@@ -103,7 +105,7 @@ public abstract class SeriesAggregationSourceNode extends 
SeriesSourceNode {
       outputColumnNames.add(ColumnHeaderConstant.ENDTIME);
     }
     outputColumnNames.addAll(
-        aggregationDescriptorList.stream()
+        getDeduplicatedDescriptors(aggregationDescriptorList).stream()
             .map(AggregationDescriptor::getOutputColumnNames)
             .flatMap(List::stream)
             .collect(Collectors.toList()));

Reply via email to