2525import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .FillNode ;
2626import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .GapFillNode ;
2727import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .PatternRecognitionNode ;
28+ import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .ProjectNode ;
2829import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .SortNode ;
2930import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .StreamSortNode ;
3031import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .ValueFillNode ;
3132import org .apache .iotdb .commons .queryengine .plan .relational .planner .node .WindowNode ;
3233import org .apache .iotdb .db .queryengine .plan .planner .plan .node .PlanVisitor ;
34+ import org .apache .iotdb .db .queryengine .plan .relational .planner .iterative .rule .PruneTableScanColumns ;
3335import org .apache .iotdb .db .queryengine .plan .relational .planner .node .DeviceTableScanNode ;
3436
37+ import com .google .common .collect .ImmutableSet ;
38+
3539import java .util .Collections ;
40+ import java .util .List ;
41+ import java .util .Optional ;
42+ import java .util .Set ;
3643
3744/**
3845 * <b>Optimization phase:</b> Distributed plan planning.
4249 * SortNode can be eliminated.
4350 * <li>When order by all IDColumns and time, the SortNode can be eliminated.
4451 * <li>When StreamSortIndex==OrderBy size()-1, remove this StreamSortNode
52+ * <li>After SortNode elimination, visitProject will remove redundant identity ProjectNodes above
53+ * TableScan and pushes column pruning into the scan.
4554 */
4655public class SortElimination implements PlanOptimizer {
4756
@@ -64,6 +73,43 @@ public PlanNode visitPlan(PlanNode node, Context context) {
6473 return newNode ;
6574 }
6675
76+ @ Override
77+ public PlanNode visitProject (ProjectNode node , Context context ) {
78+ Context newContext = new Context ();
79+ PlanNode child = node .getChild ().accept (this , newContext );
80+ context .setCannotEliminateSort (newContext .cannotEliminateSort );
81+
82+ // Remove useless ProjectNode and prune columns of TableScanNode
83+ return eliminateProjectOverTableScan (node , child )
84+ .orElseGet (() -> node .replaceChildren (Collections .singletonList (child )));
85+ }
86+
87+ private static Optional <PlanNode > eliminateProjectOverTableScan (
88+ ProjectNode project , PlanNode child ) {
89+ if (!(child instanceof DeviceTableScanNode ) || !project .isIdentity ()) {
90+ return Optional .empty ();
91+ }
92+
93+ // Notice that SortNode may have been eliminated in TableDistributedPlanGenerator
94+ DeviceTableScanNode tableScan = (DeviceTableScanNode ) child ;
95+ int projectOutputsSize = project .getOutputSymbols ().size ();
96+ int scanOutputsSize = tableScan .getOutputSymbols ().size ();
97+ if (projectOutputsSize > scanOutputsSize ) {
98+ return Optional .empty ();
99+ }
100+
101+ List <Symbol > projectOutputs = project .getOutputSymbols ();
102+ Set <Symbol > scanOutputs = ImmutableSet .copyOf (tableScan .getOutputSymbols ());
103+ if (!scanOutputs .containsAll (projectOutputs )) {
104+ return Optional .empty ();
105+ }
106+
107+ if (projectOutputsSize == scanOutputsSize ) {
108+ return Optional .of (tableScan );
109+ }
110+ return PruneTableScanColumns .pruneColumns (tableScan , ImmutableSet .copyOf (projectOutputs ));
111+ }
112+
67113 @ Override
68114 public PlanNode visitSort (SortNode node , Context context ) {
69115 Context newContext = new Context ();
@@ -75,9 +121,7 @@ public PlanNode visitSort(SortNode node, Context context) {
75121 && orderingScheme .getOrderBy ().get (0 ).getName ().equals (context .getTimeColumnName ())) {
76122 return child ;
77123 }
78- return context .canEliminateSort () && node .isOrderByAllIdsAndTime ()
79- ? child
80- : node .replaceChildren (Collections .singletonList (child ));
124+ return node .replaceChildren (Collections .singletonList (child ));
81125 }
82126
83127 @ Override
@@ -152,6 +196,8 @@ private static class Context {
152196
153197 private String timeColumnName = null ;
154198
199+ private boolean sortEliminated = false ;
200+
155201 Context () {}
156202
157203 public void addDeviceEntrySize (int deviceEntrySize ) {
@@ -177,5 +223,13 @@ public String getTimeColumnName() {
177223 public void setTimeColumnName (String timeColumnName ) {
178224 this .timeColumnName = timeColumnName ;
179225 }
226+
227+ public boolean isSortEliminated () {
228+ return sortEliminated ;
229+ }
230+
231+ public void markSortEliminated () {
232+ this .sortEliminated = true ;
233+ }
180234 }
181235}
0 commit comments