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

morrysnow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new b6605b99aa [ehancement](nereids) eliminate project in the post process 
phase (#14490)
b6605b99aa is described below

commit b6605b99aa7268c04bb51ae40e69743c8fca53ae
Author: Kikyou1997 <33112463+kikyou1...@users.noreply.github.com>
AuthorDate: Mon Nov 28 00:39:36 2022 +0800

    [ehancement](nereids) eliminate project in the post process phase (#14490)
    
    Remove those projects that used for column pruning only and don't do any 
expression calculation, So that we could avoid some redundant data copy in 
do_projection of BE side.
---
 .../glue/translator/PhysicalPlanTranslator.java    | 115 ++++++++++++++++++---
 .../nereids/processor/post/PlanPostProcessors.java |   2 +-
 .../logical/EliminateUnnecessaryProjectTest.java   |  37 ++++++-
 .../suites/nereids_syntax_p0/explain.groovy        |   6 +-
 4 files changed, 141 insertions(+), 19 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
index 05d48e9d93..3faf6b2598 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java
@@ -38,6 +38,7 @@ import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.properties.DistributionSpecHash;
 import org.apache.doris.nereids.properties.DistributionSpecHash.ShuffleType;
 import org.apache.doris.nereids.properties.OrderKey;
+import org.apache.doris.nereids.trees.expressions.Alias;
 import org.apache.doris.nereids.trees.expressions.EqualTo;
 import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
@@ -80,6 +81,7 @@ import org.apache.doris.planner.EmptySetNode;
 import org.apache.doris.planner.ExchangeNode;
 import org.apache.doris.planner.HashJoinNode;
 import org.apache.doris.planner.HashJoinNode.DistributionMode;
+import org.apache.doris.planner.JoinNodeBase;
 import org.apache.doris.planner.NestedLoopJoinNode;
 import org.apache.doris.planner.OlapScanNode;
 import org.apache.doris.planner.PlanFragment;
@@ -135,6 +137,13 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
             rootFragment = exchangeToMergeFragment(rootFragment, context);
         }
         List<Expr> outputExprs = Lists.newArrayList();
+        if (physicalPlan instanceof PhysicalProject) {
+            PhysicalProject project = (PhysicalProject) physicalPlan;
+            if (isUnnecessaryProject(project) && !projectOnAgg(project)) {
+                List<Slot> slotReferences = removeAlias(project);
+                physicalPlan = (PhysicalPlan) 
physicalPlan.child(0).withOutput(slotReferences);
+            }
+        }
         physicalPlan.getOutput().stream().map(Slot::getExprId)
                 .forEach(exprId -> 
outputExprs.add(context.findSlotRef(exprId)));
         rootFragment.setOutputExprs(outputExprs);
@@ -678,6 +687,9 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
         if (hashJoin.getOtherJoinConjuncts().isEmpty()
                 && (joinType == JoinType.LEFT_ANTI_JOIN || joinType == 
JoinType.LEFT_SEMI_JOIN)) {
             for (SlotDescriptor leftSlotDescriptor : leftSlotDescriptors) {
+                if (!leftSlotDescriptor.isMaterialized()) {
+                    continue;
+                }
                 SlotReference sf = 
leftChildOutputMap.get(context.findExprId(leftSlotDescriptor.getId()));
                 SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                 leftIntermediateSlotDescriptor.add(sd);
@@ -685,12 +697,18 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
         } else if (hashJoin.getOtherJoinConjuncts().isEmpty()
                 && (joinType == JoinType.RIGHT_ANTI_JOIN || joinType == 
JoinType.RIGHT_SEMI_JOIN)) {
             for (SlotDescriptor rightSlotDescriptor : rightSlotDescriptors) {
+                if (!rightSlotDescriptor.isMaterialized()) {
+                    continue;
+                }
                 SlotReference sf = 
rightChildOutputMap.get(context.findExprId(rightSlotDescriptor.getId()));
                 SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                 rightIntermediateSlotDescriptor.add(sd);
             }
         } else {
             for (SlotDescriptor leftSlotDescriptor : leftSlotDescriptors) {
+                if (!leftSlotDescriptor.isMaterialized()) {
+                    continue;
+                }
                 SlotReference sf = 
leftChildOutputMap.get(context.findExprId(leftSlotDescriptor.getId()));
                 SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                 if (hashOutputSlotReferenceMap.get(sf.getExprId()) != null) {
@@ -699,6 +717,9 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
                 leftIntermediateSlotDescriptor.add(sd);
             }
             for (SlotDescriptor rightSlotDescriptor : rightSlotDescriptors) {
+                if (!rightSlotDescriptor.isMaterialized()) {
+                    continue;
+                }
                 SlotReference sf = 
rightChildOutputMap.get(context.findExprId(rightSlotDescriptor.getId()));
                 SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                 if (hashOutputSlotReferenceMap.get(sf.getExprId()) != null) {
@@ -824,6 +845,9 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
             if (nestedLoopJoinNode.getConjuncts().isEmpty()
                     && (joinType == JoinType.LEFT_ANTI_JOIN || joinType == 
JoinType.LEFT_SEMI_JOIN)) {
                 for (SlotDescriptor leftSlotDescriptor : leftSlotDescriptors) {
+                    if (!leftSlotDescriptor.isMaterialized()) {
+                        continue;
+                    }
                     SlotReference sf = 
leftChildOutputMap.get(context.findExprId(leftSlotDescriptor.getId()));
                     SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                     leftIntermediateSlotDescriptor.add(sd);
@@ -831,17 +855,26 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
             } else if (nestedLoopJoinNode.getConjuncts().isEmpty()
                     && (joinType == JoinType.RIGHT_ANTI_JOIN || joinType == 
JoinType.RIGHT_SEMI_JOIN)) {
                 for (SlotDescriptor rightSlotDescriptor : 
rightSlotDescriptors) {
+                    if (!rightSlotDescriptor.isMaterialized()) {
+                        continue;
+                    }
                     SlotReference sf = 
rightChildOutputMap.get(context.findExprId(rightSlotDescriptor.getId()));
                     SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                     rightIntermediateSlotDescriptor.add(sd);
                 }
             } else {
                 for (SlotDescriptor leftSlotDescriptor : leftSlotDescriptors) {
+                    if (!leftSlotDescriptor.isMaterialized()) {
+                        continue;
+                    }
                     SlotReference sf = 
leftChildOutputMap.get(context.findExprId(leftSlotDescriptor.getId()));
                     SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                     leftIntermediateSlotDescriptor.add(sd);
                 }
                 for (SlotDescriptor rightSlotDescriptor : 
rightSlotDescriptors) {
+                    if (!rightSlotDescriptor.isMaterialized()) {
+                        continue;
+                    }
                     SlotReference sf = 
rightChildOutputMap.get(context.findExprId(rightSlotDescriptor.getId()));
                     SlotDescriptor sd = 
context.createSlotDesc(intermediateDescriptor, sf);
                     rightIntermediateSlotDescriptor.add(sd);
@@ -904,43 +937,51 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
             }
         }
         PlanFragment inputFragment = project.child(0).accept(this, context);
-
         List<Expr> execExprList = project.getProjects()
                 .stream()
                 .map(e -> ExpressionTranslator.translate(e, context))
                 .collect(Collectors.toList());
         // TODO: fix the project alias of an aliased relation.
-        List<Slot> slotList = project.getOutput();
-        TupleDescriptor tupleDescriptor = generateTupleDesc(slotList, null, 
context);
+
         PlanNode inputPlanNode = inputFragment.getPlanRoot();
+        List<Slot> slotList = project.getOutput();
         // For hash join node, use vSrcToOutputSMap to describe the expression 
calculation, use
         // vIntermediateTupleDescList as input, and set vOutputTupleDesc as 
the final output.
         // TODO: HashJoinNode's be implementation is not support projection 
yet, remove this after when supported.
-        if (inputPlanNode instanceof HashJoinNode) {
-            HashJoinNode hashJoinNode = (HashJoinNode) inputPlanNode;
+        if (inputPlanNode instanceof JoinNodeBase) {
+            TupleDescriptor tupleDescriptor = generateTupleDesc(slotList, 
null, context);
+            JoinNodeBase hashJoinNode = (JoinNodeBase) inputPlanNode;
             hashJoinNode.setvOutputTupleDesc(tupleDescriptor);
             hashJoinNode.setvSrcToOutputSMap(execExprList);
             return inputFragment;
         }
-        if (inputPlanNode instanceof NestedLoopJoinNode) {
-            NestedLoopJoinNode nestedLoopJoinNode = (NestedLoopJoinNode) 
inputPlanNode;
-            nestedLoopJoinNode.setvOutputTupleDesc(tupleDescriptor);
-            nestedLoopJoinNode.setvSrcToOutputSMap(execExprList);
-            return inputFragment;
-        }
-        inputPlanNode.setProjectList(execExprList);
-        inputPlanNode.setOutputTupleDesc(tupleDescriptor);
-
         List<Expr> predicateList = inputPlanNode.getConjuncts();
         Set<Integer> requiredSlotIdList = new HashSet<>();
         for (Expr expr : predicateList) {
             extractExecSlot(expr, requiredSlotIdList);
         }
+        boolean nonPredicate = CollectionUtils.isEmpty(requiredSlotIdList);
         for (Expr expr : execExprList) {
             extractExecSlot(expr, requiredSlotIdList);
         }
+        if (!hasExprCalc(project) && (!hasPrune(project) || nonPredicate) && 
!projectOnAgg(project)) {
+            List<NamedExpression> namedExpressions = project.getProjects();
+            for (int i = 0; i < namedExpressions.size(); i++) {
+                NamedExpression n = namedExpressions.get(i);
+                for (Expression e : n.children()) {
+                    SlotReference slotReference = (SlotReference) e;
+                    SlotRef slotRef = 
context.findSlotRef(slotReference.getExprId());
+                    context.addExprIdSlotRefPair(slotList.get(i).getExprId(), 
slotRef);
+                }
+            }
+        } else {
+            TupleDescriptor tupleDescriptor = generateTupleDesc(slotList, 
null, context);
+            inputPlanNode.setProjectList(execExprList);
+            inputPlanNode.setOutputTupleDesc(tupleDescriptor);
+        }
         if (inputPlanNode instanceof OlapScanNode) {
             updateChildSlotsMaterialization(inputPlanNode, requiredSlotIdList, 
context);
+            return inputFragment;
         }
         return inputFragment;
     }
@@ -1249,4 +1290,50 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
                 .map(slot -> slot.getId().asInt())
                 .collect(ImmutableList.toImmutableList());
     }
+
+    private boolean isUnnecessaryProject(PhysicalProject project) {
+        // The project list for agg is always needed,since tuple of agg 
contains the slots used by group by expr
+        return !hasPrune(project) && !hasExprCalc(project);
+    }
+
+    private boolean hasPrune(PhysicalProject project) {
+        PhysicalPlan child = (PhysicalPlan) project.child(0);
+
+        return project.getProjects().size() != child.getOutput().size();
+    }
+
+    private boolean projectOnAgg(PhysicalProject project) {
+        PhysicalPlan child = (PhysicalPlan) project.child(0);
+        while (child instanceof PhysicalFilter || child instanceof 
PhysicalDistribute) {
+            child = (PhysicalPlan) child.child(0);
+        }
+        return child instanceof PhysicalAggregate;
+    }
+
+    private boolean hasExprCalc(PhysicalProject<? extends Plan> project) {
+        for (NamedExpression p : project.getProjects()) {
+            if (p.children().size() > 1) {
+                return true;
+            }
+            for (Expression e : p.children()) {
+                if (!(e instanceof SlotReference)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private List<Slot> removeAlias(PhysicalProject project) {
+        List<NamedExpression> namedExpressions = project.getProjects();
+        List<Slot> slotReferences = new ArrayList<>();
+        for (NamedExpression n : namedExpressions) {
+            if (n instanceof Alias) {
+                slotReferences.add((SlotReference) n.child(0));
+            } else {
+                slotReferences.add((SlotReference) n);
+            }
+        }
+        return slotReferences;
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/PlanPostProcessors.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/PlanPostProcessors.java
index 23fec67a58..269dc94be1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/PlanPostProcessors.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/processor/post/PlanPostProcessors.java
@@ -46,7 +46,7 @@ public class PlanPostProcessors {
     public PhysicalPlan process(PhysicalPlan physicalPlan) {
         PhysicalPlan resultPlan = physicalPlan;
         for (PlanPostProcessor processor : getProcessors()) {
-            resultPlan = (PhysicalPlan) physicalPlan.accept(processor, 
cascadesContext);
+            resultPlan = (PhysicalPlan) resultPlan.accept(processor, 
cascadesContext);
         }
         return resultPlan;
     }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/EliminateUnnecessaryProjectTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/EliminateUnnecessaryProjectTest.java
index babcd5caf6..7234cf73b1 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/EliminateUnnecessaryProjectTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/logical/EliminateUnnecessaryProjectTest.java
@@ -26,19 +26,39 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
 import org.apache.doris.nereids.util.LogicalPlanBuilder;
 import org.apache.doris.nereids.util.MemoTestUtils;
+import org.apache.doris.nereids.util.PlanChecker;
 import org.apache.doris.nereids.util.PlanConstructor;
+import org.apache.doris.planner.OlapScanNode;
+import org.apache.doris.planner.PlanFragment;
+import org.apache.doris.utframe.TestWithFeService;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * test ELIMINATE_UNNECESSARY_PROJECT rule.
  */
-public class EliminateUnnecessaryProjectTest {
+public class EliminateUnnecessaryProjectTest extends TestWithFeService {
+
+    @Override
+    protected void runBeforeAll() throws Exception {
+        createDatabase("test");
+
+        connectContext.setDatabase("default_cluster:test");
+
+        createTable("CREATE TABLE t1 (col1 int not null, col2 int not null, 
col3 int not null)\n"
+                + "DISTRIBUTED BY HASH(col3)\n"
+                + "BUCKETS 1\n"
+                + "PROPERTIES(\n"
+                + "    \"replication_num\"=\"1\"\n"
+                + ");");
+    }
 
     @Test
     public void testEliminateNonTopUnnecessaryProject() {
@@ -82,4 +102,19 @@ public class EliminateUnnecessaryProjectTest {
         Plan actual = cascadesContext.getMemo().copyOut();
         Assertions.assertTrue(actual instanceof LogicalProject);
     }
+
+    @Test
+    public void testEliminationForThoseNeitherDoPruneNorDoExprCalc() {
+        PlanChecker.from(connectContext).checkPlannerResult("SELECT col1 FROM 
t1",
+                p -> {
+                    List<PlanFragment> fragments = p.getFragments();
+                    Assertions.assertTrue(fragments.stream()
+                            .flatMap(fragment -> {
+                                Set<OlapScanNode> scans = Sets.newHashSet();
+                                
fragment.getPlanRoot().collect(OlapScanNode.class, scans);
+                                return scans.stream();
+                            })
+                            .noneMatch(s -> s.getProjectList() != null));
+                });
+    }
 }
diff --git a/regression-test/suites/nereids_syntax_p0/explain.groovy 
b/regression-test/suites/nereids_syntax_p0/explain.groovy
index e588b510f3..f265bbebde 100644
--- a/regression-test/suites/nereids_syntax_p0/explain.groovy
+++ b/regression-test/suites/nereids_syntax_p0/explain.groovy
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-suite("explain") {
+suite("nereids_explain") {
     sql """
         SET enable_vectorized_engine=true
     """
@@ -28,8 +28,8 @@ suite("explain") {
 
     explain {
         sql("select count(2) + 1, sum(2) + sum(lo_suppkey) from lineorder")
-        contains "projections: lo_suppkey"
-        contains "project output tuple id: 1"
+        contains "(sum(2) + sum(lo_suppkey))[#24]"
+        contains "project output tuple id: 3"
     }
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to