@Override
  public List<PlanNode> visitTreeDeviceViewScan(TreeDeviceViewScanNode node, PlanContext context) {
    DataPartition dataPartition = analysis.getDataPartitionInfo();
    if (dataPartition == null || node.getTreeDBName() == null) {
      node.setRegionReplicaSet(NOT_ASSIGNED);
      return Collections.singletonList(node);
    }

    String dbName = node.getTreeDBName();
    Map<TSeriesPartitionSlot, Map<TTimePartitionSlot, List<TRegionReplicaSet>>> seriesSlotMap =
        dataPartition.getDataPartitionMap().get(dbName);
    if (seriesSlotMap == null) {
      throw new SemanticException(
          String.format("Given queried database: %s is not exist!", dbName));
    }

    Map<TRegionReplicaSet, Pair<TreeAlignedDeviceViewScanNode, TreeNonAlignedDeviceViewScanNode>>
        tableScanNodeMap = new HashMap<>();
    Map<Integer, List<TRegionReplicaSet>> cachedSeriesSlotWithRegions = new HashMap<>();
    for (DeviceEntry deviceEntry : node.getDeviceEntries()) {
      List<TRegionReplicaSet> regionReplicaSets =
          getDeviceReplicaSets(
              dataPartition,
              seriesSlotMap,
              deviceEntry.getDeviceID(),
              node.getTimeFilter(),
              cachedSeriesSlotWithRegions);

      for (TRegionReplicaSet regionReplicaSet : regionReplicaSets) {
        boolean aligned = deviceEntry instanceof AlignedDeviceEntry;
        Pair<TreeAlignedDeviceViewScanNode, TreeNonAlignedDeviceViewScanNode> pair =
            tableScanNodeMap.computeIfAbsent(regionReplicaSet, k -> new Pair<>(null, null));

        if (pair.left == null && aligned) {
          TreeAlignedDeviceViewScanNode scanNode =
              new TreeAlignedDeviceViewScanNode(
                  queryId.genPlanNodeId(),
                  node.getQualifiedObjectName(),
                  node.getOutputSymbols(),
                  node.getAssignments(),
                  new ArrayList<>(),
                  node.getTagAndAttributeIndexMap(),
                  node.getScanOrder(),
                  node.getTimePredicate().orElse(null),
                  node.getPushDownPredicate(),
                  node.getPushDownLimit(),
                  node.getPushDownOffset(),
                  node.isPushLimitToEachDevice(),
                  node.containsNonAlignedDevice(),
                  node.getTreeDBName(),
                  node.getMeasurementColumnNameMap());
          scanNode.setRegionReplicaSet(regionReplicaSet);
          pair.left = scanNode;
        }

        if (pair.right == null && !aligned) {
          TreeNonAlignedDeviceViewScanNode scanNode =
              new TreeNonAlignedDeviceViewScanNode(
                  queryId.genPlanNodeId(),
                  node.getQualifiedObjectName(),
                  node.getOutputSymbols(),
                  node.getAssignments(),
                  new ArrayList<>(),
                  node.getTagAndAttributeIndexMap(),
                  node.getScanOrder(),
                  node.getTimePredicate().orElse(null),
                  node.getPushDownPredicate(),
                  node.getPushDownLimit(),
                  node.getPushDownOffset(),
                  node.isPushLimitToEachDevice(),
                  node.containsNonAlignedDevice(),
                  node.getTreeDBName(),
                  node.getMeasurementColumnNameMap());
          scanNode.setRegionReplicaSet(regionReplicaSet);
          pair.right = scanNode;
        }

        if (aligned) {
          pair.left.appendDeviceEntry(deviceEntry);
        } else {
          pair.right.appendDeviceEntry(deviceEntry);
        }
      }
    }

    if (tableScanNodeMap.isEmpty()) {
      node.setRegionReplicaSet(NOT_ASSIGNED);
      return Collections.singletonList(node);
    }

    List<PlanNode> resultTableScanNodeList = new ArrayList<>();
    TRegionReplicaSet mostUsedDataRegion = null;
    int maxDeviceEntrySizeOfTableScan = 0;
    for (Map.Entry<
            TRegionReplicaSet,
            Pair<TreeAlignedDeviceViewScanNode, TreeNonAlignedDeviceViewScanNode>>
        entry : topology.filterReachableCandidates(tableScanNodeMap.entrySet())) {
      TRegionReplicaSet regionReplicaSet = entry.getKey();
      Pair<TreeAlignedDeviceViewScanNode, TreeNonAlignedDeviceViewScanNode> pair = entry.getValue();
      int currentDeviceEntrySize = 0;

      if (pair.left != null) {
        currentDeviceEntrySize += pair.left.getDeviceEntries().size();
        resultTableScanNodeList.add(pair.left);
      }

      if (pair.right != null) {
        currentDeviceEntrySize += pair.right.getDeviceEntries().size();
        resultTableScanNodeList.add(pair.right);
      }

      if (mostUsedDataRegion == null || currentDeviceEntrySize > maxDeviceEntrySizeOfTableScan) {
        mostUsedDataRegion = regionReplicaSet;
        maxDeviceEntrySizeOfTableScan = currentDeviceEntrySize;
      }
    }
    if (mostUsedDataRegion == null) {
      throw new RootFIPlacementException(tableScanNodeMap.keySet());
    }
    context.mostUsedRegion = mostUsedDataRegion;

    if (!context.hasSortProperty) {
      return resultTableScanNodeList;
    }

    processSortProperty(node, resultTableScanNodeList, context);
    return resultTableScanNodeList;
  }
This class is used to generate distributed plan for table model.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableDistributedPlanGenerator.java