private PlanNode visitAggregation() {
    // group by level and group by tag is not allowed in align by device
    boolean outputPartial =
        queryStatement.isGroupByTime() && analysis.getGroupByTimeParameter().hasOverlap();
    AggregationStep curStep = outputPartial ? AggregationStep.PARTIAL : AggregationStep.SINGLE;
    aggregationDescriptorList =
        constructAggregationDescriptorList(analysis.getAggregationExpressions(), curStep);
    updateTypeProvider(analysis.getAggregationExpressions());
    if (curStep.isOutputPartial()) {
      aggregationDescriptorList.forEach(
          aggregationDescriptor ->
              updateTypeProviderByPartialAggregation(
                  aggregationDescriptor, context.getTypeProvider()));
    }

    LogicalPlanBuilder templatedPlanBuilder =
        new TemplatedLogicalPlanBuilder(analysis, context, measurementList, schemaList);
    Map<IDeviceID, PlanNode> deviceToSubPlanMap = new LinkedHashMap<>();
    aggregationDescriptorList = getDeduplicatedDescriptors(aggregationDescriptorList);

    boolean needCheckAscending = queryStatement.isGroupByTime();
    List<AggregationDescriptor> ascendingDescriptors = new ArrayList<>();
    List<AggregationDescriptor> descendingDescriptors = new ArrayList<>();
    for (AggregationDescriptor aggregationDescriptor : aggregationDescriptorList) {
      if (needCheckAscending
          || SchemaUtils.isConsistentWithScanOrder(
              aggregationDescriptor.getAggregationType(), queryStatement.getResultTimeOrder())) {
        ascendingDescriptors.add(aggregationDescriptor);
      } else {
        descendingDescriptors.add(aggregationDescriptor);
      }
    }
    context.getTypeProvider().getTemplatedInfo().setAscendingDescriptorList(ascendingDescriptors);
    context.getTypeProvider().getTemplatedInfo().setDescendingDescriptorList(descendingDescriptors);

    for (PartialPath devicePath : analysis.getDeviceList()) {
      IDeviceID deviceName = devicePath.getIDeviceID();
      PlanNode rootNode = visitDeviceAggregationBody(devicePath);

      LogicalPlanBuilder subPlanBuilder =
          new TemplatedLogicalPlanBuilder(analysis, context, measurementList, schemaList)
              .withNewRoot(rootNode);

      deviceToSubPlanMap.put(deviceName, subPlanBuilder.getRoot());
    }

    templatedPlanBuilder =
        templatedPlanBuilder
            .planDeviceView(
                deviceToSubPlanMap,
                analysis.getDeviceViewOutputExpressions(),
                null,
                analysis.getSelectExpressions(),
                queryStatement,
                analysis)
            .planHavingAndTransform(
                analysis.getHavingExpression(),
                analysis.getSelectExpressions(),
                analysis.getOrderByExpressions(),
                queryStatement.isGroupByTime(),
                queryStatement.getResultTimeOrder());

    if (!queryStatement.needPushDownSort()) {
      templatedPlanBuilder = templatedPlanBuilder.planOrderBy(queryStatement, analysis);
    }

    templatedPlanBuilder =
        templatedPlanBuilder
            .planFill(analysis.getFillDescriptor(), queryStatement.getResultTimeOrder())
            .planOffset(queryStatement.getRowOffset());

    if (!analysis.isUseTopKNode() || queryStatement.hasOffset()) {
      templatedPlanBuilder = templatedPlanBuilder.planLimit(queryStatement.getRowLimit());
    }

    return templatedPlanBuilder.getRoot();
  }
This class provides accelerated implementation for multiple devices align by device query. This
optimization is only used for devices set in only one template, using template can avoid many
unnecessary judgements.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/TemplatedLogicalPlan.java