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

huajianlan 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 f2923f9180 [Refactor](Nereids) Simplify get input and output slots for 
plan/expression. (#12356)
f2923f9180 is described below

commit f2923f9180899a04a2575179bdadcb9ed8feaf3a
Author: Shuo Wang <[email protected]>
AuthorDate: Wed Sep 7 14:05:37 2022 +0800

    [Refactor](Nereids) Simplify get input and output slots for 
plan/expression. (#12356)
    
    Simplify the code of getting input/output slots from `Expression` or `Plan`.
    
    **new interfaces add**
    
    `Expression`:
    `getInputSlots`: Get all the input slots of the expression.
    
    `Plan`:
    - `getOutputSet`: Get the output slot set of the plan.
    - `getInputSlots`: Get the input slot set of the plan.
    
    **changed interface**
    
    `TreeNode`:
    - `collect`: return `set` as result instead of `list`.
---
 .../doris/nereids/analyzer/UnboundRelation.java    |  4 +-
 .../glue/translator/PhysicalPlanTranslator.java    |  6 +-
 .../properties/UnboundLogicalProperties.java       |  4 +-
 .../nereids/rules/analysis/AnalyzeSubquery.java    |  5 +-
 .../nereids/rules/analysis/BindSlotReference.java  |  6 +-
 .../rules/exploration/join/JoinLAsscomHelper.java  | 19 +++---
 .../rules/rewrite/AggregateDisassemble.java        |  3 +-
 .../logical/AbstractPushDownProjectRule.java       | 14 +----
 .../nereids/rules/rewrite/logical/MultiJoin.java   |  5 +-
 .../rules/rewrite/logical/NormalizeAggregate.java  |  4 +-
 .../rewrite/logical/PruneAggChildColumns.java      |  9 +--
 .../rewrite/logical/PruneFilterChildColumns.java   | 15 +++--
 .../rewrite/logical/PruneJoinChildrenColumns.java  | 15 ++---
 .../rewrite/logical/PruneOlapScanPartition.java    |  6 +-
 .../rewrite/logical/PruneSortChildColumns.java     |  3 +-
 .../logical/PushPredicateThroughAggregation.java   |  3 +-
 .../rewrite/logical/PushPredicateThroughJoin.java  |  7 +--
 .../apache/doris/nereids/stats/JoinEstimation.java |  4 +-
 .../doris/nereids/stats/StatsCalculator.java       | 13 +++--
 .../org/apache/doris/nereids/trees/TreeNode.java   |  3 +-
 .../nereids/trees/expressions/Expression.java      | 17 ++++++
 .../doris/nereids/trees/plans/AbstractPlan.java    | 45 +++++---------
 .../org/apache/doris/nereids/trees/plans/Plan.java | 29 +++++++++
 .../trees/plans/logical/AbstractLogicalPlan.java   | 15 +++--
 .../trees/plans/logical/LogicalAggregate.java      |  3 +-
 .../nereids/trees/plans/logical/LogicalApply.java  |  2 +-
 .../trees/plans/logical/LogicalAssertNumRows.java  |  2 +-
 .../nereids/trees/plans/logical/LogicalBinary.java | 10 ----
 .../nereids/trees/plans/logical/LogicalFilter.java |  2 +-
 .../nereids/trees/plans/logical/LogicalHaving.java |  2 +-
 .../nereids/trees/plans/logical/LogicalJoin.java   |  8 ++-
 .../nereids/trees/plans/logical/LogicalLeaf.java   |  5 --
 .../nereids/trees/plans/logical/LogicalLimit.java  |  2 +-
 .../trees/plans/logical/LogicalOlapScan.java       |  4 +-
 .../trees/plans/logical/LogicalProject.java        |  2 +-
 .../trees/plans/logical/LogicalSelectHint.java     |  2 +-
 .../nereids/trees/plans/logical/LogicalSort.java   |  2 +-
 .../trees/plans/logical/LogicalSubQueryAlias.java  |  2 +-
 .../nereids/trees/plans/logical/LogicalTopN.java   |  3 +-
 .../nereids/trees/plans/logical/LogicalUnary.java  |  9 ---
 .../trees/plans/physical/AbstractPhysicalJoin.java |  7 ++-
 .../trees/plans/physical/AbstractPhysicalPlan.java |  6 --
 .../trees/plans/physical/PhysicalAggregate.java    |  6 +-
 .../plans/physical/PhysicalAssertNumRows.java      |  8 +--
 .../trees/plans/physical/PhysicalDistribute.java   |  6 +-
 .../trees/plans/physical/PhysicalFilter.java       |  6 +-
 .../trees/plans/physical/PhysicalHashJoin.java     |  6 +-
 .../trees/plans/physical/PhysicalLimit.java        |  6 +-
 .../plans/physical/PhysicalLocalQuickSort.java     |  6 +-
 .../plans/physical/PhysicalNestedLoopJoin.java     |  6 +-
 .../trees/plans/physical/PhysicalOlapScan.java     |  4 +-
 .../trees/plans/physical/PhysicalProject.java      |  6 +-
 .../trees/plans/physical/PhysicalQuickSort.java    |  7 ++-
 .../nereids/trees/plans/physical/PhysicalTopN.java |  6 +-
 .../apache/doris/nereids/util/ExpressionUtils.java | 15 -----
 .../org/apache/doris/nereids/util/JoinUtils.java   | 38 +++++-------
 .../apache/doris/nereids/util/SlotExtractor.java   | 68 ----------------------
 .../doris/nereids/jobs/RewriteTopDownJobTest.java  |  2 +-
 58 files changed, 217 insertions(+), 306 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
index 4c6c7f2c47..f654bcb089 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
@@ -83,12 +83,12 @@ public class UnboundRelation extends LogicalLeaf implements 
Unbound {
 
     @Override
     public LogicalProperties computeLogicalProperties() {
-        return new UnboundLogicalProperties();
+        return UnboundLogicalProperties.INSTANCE;
     }
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new UnboundRelation(nameParts, groupExpression, 
Optional.of(logicalProperties));
+        return new UnboundRelation(nameParts, groupExpression, 
Optional.of(getLogicalProperties()));
     }
 
     @Override
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 bea235d238..d35bc6dd87 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
@@ -166,8 +166,8 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
         List<AggregateFunction> aggregateFunctionList = 
outputExpressionList.stream()
                 .filter(o -> o.anyMatch(AggregateFunction.class::isInstance))
                 .peek(o -> aggFunctionOutput.add(o.toSlot()))
-                .map(o -> 
o.<List<AggregateFunction>>collect(AggregateFunction.class::isInstance))
-                .flatMap(List::stream)
+                .map(o -> 
o.<Set<AggregateFunction>>collect(AggregateFunction.class::isInstance))
+                .flatMap(Set::stream)
                 .collect(Collectors.toList());
         ArrayList<FunctionCallExpr> execAggregateFunctions = 
aggregateFunctionList.stream()
                 .map(x -> (FunctionCallExpr) ExpressionTranslator.translate(x, 
context))
@@ -383,7 +383,7 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
 
         List<Expr> execEqConjuncts = hashJoin.getHashJoinConjuncts().stream()
                 .map(EqualTo.class::cast)
-                .map(e -> JoinUtils.swapEqualToForChildrenOrder(e, 
hashJoin.left().getOutput()))
+                .map(e -> JoinUtils.swapEqualToForChildrenOrder(e, 
hashJoin.left().getOutputSet()))
                 .map(e -> ExpressionTranslator.translate(e, context))
                 .collect(Collectors.toList());
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/UnboundLogicalProperties.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/UnboundLogicalProperties.java
index 015e53c48b..a086e54e7a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/UnboundLogicalProperties.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/UnboundLogicalProperties.java
@@ -29,7 +29,9 @@ import java.util.List;
  * so UnboundRelation.computeLogicalProperties() return a 
UnboundLogicalProperties temporary.
  */
 public class UnboundLogicalProperties extends LogicalProperties {
-    public UnboundLogicalProperties() {
+    public static final UnboundLogicalProperties INSTANCE = new 
UnboundLogicalProperties();
+
+    private UnboundLogicalProperties() {
         super(ImmutableList::of);
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
index 461b83298d..cbffb53611 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalyzeSubquery.java
@@ -38,6 +38,7 @@ import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 
 /**
  * AnalyzeSubquery. translate from subquery to LogicalApply.
@@ -52,7 +53,7 @@ public class AnalyzeSubquery implements AnalysisRuleFactory {
                 RuleType.ANALYZE_FILTER_SUBQUERY.build(
                         logicalFilter().thenApply(ctx -> {
                             LogicalFilter filter = ctx.root;
-                            List<SubqueryExpr> subqueryExprs = 
filter.getPredicates()
+                            Set<SubqueryExpr> subqueryExprs = 
filter.getPredicates()
                                     .collect(SubqueryExpr.class::isInstance);
                             if (subqueryExprs.isEmpty()) {
                                 return filter;
@@ -69,7 +70,7 @@ public class AnalyzeSubquery implements AnalysisRuleFactory {
         );
     }
 
-    private LogicalPlan analyzedSubquery(List<SubqueryExpr> subqueryExprs,
+    private LogicalPlan analyzedSubquery(Set<SubqueryExpr> subqueryExprs,
             LogicalPlan childPlan, CascadesContext ctx) {
         LogicalPlan tmpPlan = childPlan;
         for (SubqueryExpr subqueryExpr : subqueryExprs) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
index c5c7503c4d..282e119fe5 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java
@@ -107,8 +107,12 @@ public class BindSlotReference implements 
AnalysisRuleFactory {
                     LogicalJoin<GroupPlan, GroupPlan> join = ctx.root;
                     Optional<Expression> cond = join.getOtherJoinCondition()
                             .map(expr -> bind(expr, join.children(), join, 
ctx.cascadesContext));
+
+                    List<Expression> hashJoinConjuncts = 
join.getHashJoinConjuncts().stream()
+                            .map(expr -> bind(expr, join.children(), join, 
ctx.cascadesContext))
+                            .collect(Collectors.toList());
                     return new LogicalJoin<>(join.getJoinType(),
-                            ImmutableList.of(), cond, join.left(), 
join.right());
+                            hashJoinConjuncts, cond, join.left(), 
join.right());
                 })
             ),
             RuleType.BINDING_AGGREGATE_SLOT.build(
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinLAsscomHelper.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinLAsscomHelper.java
index 675905cf9f..e6fe676406 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinLAsscomHelper.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinLAsscomHelper.java
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.rules.exploration.join;
 import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -34,6 +35,7 @@ import com.google.common.collect.Lists;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 
 /**
  * Common function for JoinLAsscom
@@ -109,11 +111,10 @@ public class JoinLAsscomHelper {
         for (Expression topJoinOnClauseConjunct : topHashJoinConjuncts) {
             // Ignore join with some OnClause like:
             // Join C = B + A for above example.
-            List<SlotReference> topJoinUsedSlot = 
topJoinOnClauseConjunct.collect(SlotReference.class::isInstance);
-            if (ExpressionUtils.isIntersecting(topJoinUsedSlot, aOutputSlots)
-                    && ExpressionUtils.isIntersecting(topJoinUsedSlot, 
bOutputSlots)
-                    && ExpressionUtils.isIntersecting(topJoinUsedSlot, 
cOutputSlots)
-            ) {
+            Set<Slot> topJoinUsedSlot = 
topJoinOnClauseConjunct.getInputSlots();
+            if (topJoinUsedSlot.containsAll(aOutputSlots)
+                    && topJoinUsedSlot.containsAll(bOutputSlots)
+                    && topJoinUsedSlot.containsAll(cOutputSlots)) {
                 return false;
             }
         }
@@ -122,11 +123,11 @@ public class JoinLAsscomHelper {
         allHashJoinConjuncts.addAll(topHashJoinConjuncts);
         allHashJoinConjuncts.addAll(bottomHashJoinConjuncts);
 
-        HashSet<SlotReference> newBottomJoinSlots = new 
HashSet<>(aOutputSlots);
+        Set<Slot> newBottomJoinSlots = new HashSet<>(aOutputSlots);
         newBottomJoinSlots.addAll(cOutputSlots);
 
         for (Expression hashConjunct : allHashJoinConjuncts) {
-            List<SlotReference> slots = 
hashConjunct.collect(SlotReference.class::isInstance);
+            Set<Slot> slots = hashConjunct.getInputSlots();
             if (newBottomJoinSlots.containsAll(slots)) {
                 newBottomHashJoinConjuncts.add(hashConjunct);
             } else {
@@ -134,7 +135,7 @@ public class JoinLAsscomHelper {
             }
         }
         for (Expression nonHashConjunct : allNonHashJoinConjuncts) {
-            List<SlotReference> slots = 
nonHashConjunct.collect(SlotReference.class::isInstance);
+            Set<SlotReference> slots = 
nonHashConjunct.collect(SlotReference.class::isInstance);
             if (newBottomJoinSlots.containsAll(slots)) {
                 newBottomNonHashJoinConjuncts.add(nonHashConjunct);
             } else {
@@ -168,7 +169,7 @@ public class JoinLAsscomHelper {
 
         HashSet<SlotReference> bOutputSlotsSet = new HashSet<>(bOutputSlots);
         for (NamedExpression projectExpr : projectExprs) {
-            List<SlotReference> usedSlotRefs = 
projectExpr.collect(SlotReference.class::isInstance);
+            Set<SlotReference> usedSlotRefs = 
projectExpr.collect(SlotReference.class::isInstance);
             if (bOutputSlotsSet.containsAll(usedSlotRefs)) {
                 newRightProjectExprs.add(projectExpr);
             } else {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AggregateDisassemble.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AggregateDisassemble.java
index 1e8da9a14f..87363e4273 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AggregateDisassemble.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/AggregateDisassemble.java
@@ -34,6 +34,7 @@ import com.google.common.collect.Maps;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -95,7 +96,7 @@ public class AggregateDisassemble extends 
OneRewriteRuleFactory {
                 }
             }
             for (NamedExpression originOutputExpr : originOutputExprs) {
-                List<AggregateFunction> aggregateFunctions
+                Set<AggregateFunction> aggregateFunctions
                         = 
originOutputExpr.collect(AggregateFunction.class::isInstance);
                 for (AggregateFunction aggregateFunction : aggregateFunctions) 
{
                     if (inputSubstitutionMap.containsKey(aggregateFunction)) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/AbstractPushDownProjectRule.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/AbstractPushDownProjectRule.java
index 2b28c488d5..c916dde6b3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/AbstractPushDownProjectRule.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/AbstractPushDownProjectRule.java
@@ -21,15 +21,9 @@ import org.apache.doris.nereids.pattern.PatternDescriptor;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleType;
 import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
-import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.util.SlotExtractor;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -42,12 +36,8 @@ public abstract class AbstractPushDownProjectRule<C extends 
Plan> extends OneRew
 
     @Override
     public Rule build() {
-        return logicalProject(target).then(project -> {
-            List<Expression> projects = Lists.newArrayList();
-            projects.addAll(project.getProjects());
-            Set<Slot> projectSlots = SlotExtractor.extractSlot(projects);
-            return 
project.withChildren(ImmutableList.of(pushDownProject(project.child(), 
projectSlots)));
-        }).toRule(ruleType);
+        return logicalProject(target).then(project -> project.withChildren(
+                pushDownProject(project.child(), 
project.getInputSlots()))).toRule(ruleType);
     }
 
     protected abstract Plan pushDownProject(C plan, Set<Slot> references);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/MultiJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/MultiJoin.java
index dcab77a8b0..7fda8114ed 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/MultiJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/MultiJoin.java
@@ -29,7 +29,6 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 import org.apache.doris.nereids.util.ExpressionUtils;
 import org.apache.doris.nereids.util.JoinUtils;
-import org.apache.doris.nereids.util.SlotExtractor;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -121,7 +120,7 @@ public class MultiJoin extends PlanVisitor<Void, Void> {
             Set<Slot> joinOutput = getJoinOutput(left, right);
             Optional<Expression> joinCond = conjuncts.stream()
                     .filter(expr -> {
-                        Set<Slot> exprInputSlots = 
SlotExtractor.extractSlot(expr);
+                        Set<Slot> exprInputSlots = expr.getInputSlots();
                         if (exprInputSlots.isEmpty()) {
                             return false;
                         }
@@ -166,7 +165,7 @@ public class MultiJoin extends PlanVisitor<Void, Void> {
     private Map<Boolean, List<Expression>> splitConjuncts(List<Expression> 
conjuncts, Set<Slot> slots) {
         return conjuncts.stream().collect(Collectors.partitioningBy(
                 // TODO: support non equal to conditions.
-                expr -> expr instanceof EqualTo && 
slots.containsAll(SlotExtractor.extractSlot(expr))));
+                expr -> expr instanceof EqualTo && 
slots.containsAll(expr.getInputSlots())));
     }
 
     private Set<Slot> getJoinOutput(Plan left, Plan right) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
index 0343ae4028..4d42fff964 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/NormalizeAggregate.java
@@ -105,7 +105,7 @@ public class NormalizeAggregate extends 
OneRewriteRuleFactory {
             if (partitionedOutputs.containsKey(true)) {
                 // process expressions that contain aggregate function
                 Set<AggregateFunction> aggregateFunctions = 
partitionedOutputs.get(true).stream()
-                        .flatMap(e -> 
e.<List<AggregateFunction>>collect(AggregateFunction.class::isInstance).stream())
+                        .flatMap(e -> 
e.<Set<AggregateFunction>>collect(AggregateFunction.class::isInstance).stream())
                         .collect(Collectors.toSet());
                 newOutputs.addAll(aggregateFunctions.stream()
                         .map(f -> new Alias(f, f.toSql()))
@@ -113,7 +113,7 @@ public class NormalizeAggregate extends 
OneRewriteRuleFactory {
                         .collect(Collectors.toList()));
                 // add slot references in aggregate function to bottom 
projections
                 bottomProjections.addAll(aggregateFunctions.stream()
-                        .flatMap(f -> 
f.<List<SlotReference>>collect(SlotReference.class::isInstance).stream())
+                        .flatMap(f -> 
f.<Set<SlotReference>>collect(SlotReference.class::isInstance).stream())
                         .map(SlotReference.class::cast)
                         .collect(Collectors.toSet()));
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneAggChildColumns.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneAggChildColumns.java
index 0175f909ab..b84d885e3a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneAggChildColumns.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneAggChildColumns.java
@@ -20,17 +20,14 @@ package org.apache.doris.nereids.rules.rewrite.logical;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleType;
 import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory;
-import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
-import org.apache.doris.nereids.util.SlotExtractor;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 
 import java.util.List;
 import java.util.Set;
@@ -65,10 +62,8 @@ public class PruneAggChildColumns extends 
OneRewriteRuleFactory {
                 }
                 return agg.withChildren(ImmutableList.of(new 
LogicalProject<>(ImmutableList.of(slot), agg.child())));
             }
-            List<Expression> slots = Lists.newArrayList();
-            slots.addAll(agg.getExpressions());
-            Set<Slot> outputs = SlotExtractor.extractSlot(slots);
-            List<NamedExpression> prunedOutputs = 
childOutput.stream().filter(outputs::contains)
+            Set<Slot> aggInputSlots = agg.getInputSlots();
+            List<NamedExpression> prunedOutputs = 
childOutput.stream().filter(aggInputSlots::contains)
                     .collect(Collectors.toList());
             if (prunedOutputs.size() == agg.child().getOutput().size()) {
                 return agg;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneFilterChildColumns.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneFilterChildColumns.java
index 391f6f894f..bcd925338e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneFilterChildColumns.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneFilterChildColumns.java
@@ -23,7 +23,6 @@ import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
-import org.apache.doris.nereids.util.SlotExtractor;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -60,14 +59,14 @@ public class PruneFilterChildColumns extends 
AbstractPushDownProjectRule<Logical
     }
 
     @Override
-    protected Plan pushDownProject(LogicalFilter<GroupPlan> filterPlan, 
Set<Slot> references) {
-        Set<Slot> filterSlots = 
SlotExtractor.extractSlot(filterPlan.getPredicates());
-        Set<Slot> required = Stream.concat(references.stream(), 
filterSlots.stream()).collect(Collectors.toSet());
-        if (required.containsAll(filterPlan.child().getOutput())) {
-            return filterPlan;
+    protected Plan pushDownProject(LogicalFilter<GroupPlan> filter, Set<Slot> 
references) {
+        Set<Slot> filterInputSlots = filter.getInputSlots();
+        Set<Slot> required = Stream.concat(references.stream(), 
filterInputSlots.stream()).collect(Collectors.toSet());
+        if (required.containsAll(filter.child().getOutput())) {
+            return filter;
         }
-        return filterPlan.withChildren(
-            ImmutableList.of(new 
LogicalProject<>(Lists.newArrayList(required), filterPlan.child()))
+        return filter.withChildren(
+            ImmutableList.of(new 
LogicalProject<>(Lists.newArrayList(required), filter.child()))
         );
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneJoinChildrenColumns.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneJoinChildrenColumns.java
index cdec1adee1..e76a832c2d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneJoinChildrenColumns.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneJoinChildrenColumns.java
@@ -19,20 +19,19 @@ package org.apache.doris.nereids.rules.rewrite.logical;
 
 import org.apache.doris.nereids.rules.RuleType;
 import org.apache.doris.nereids.trees.expressions.ExprId;
-import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
-import org.apache.doris.nereids.util.SlotExtractor;
 
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * prune join children output.
@@ -66,13 +65,11 @@ public class PruneJoinChildrenColumns
     @Override
     protected Plan pushDownProject(LogicalJoin<GroupPlan, GroupPlan> joinPlan,
             Set<Slot> references) {
-        if (joinPlan.getOtherJoinCondition().isPresent()) {
-            
references.addAll(SlotExtractor.extractSlot(joinPlan.getOtherJoinCondition().get()));
-        }
-        for (Expression expr : joinPlan.getHashJoinConjuncts()) {
-            references.addAll(SlotExtractor.extractSlot(expr));
-        }
-        Set<ExprId> exprIds = 
references.stream().map(NamedExpression::getExprId).collect(Collectors.toSet());
+
+        Set<ExprId> exprIds = Stream.of(references, joinPlan.getInputSlots())
+                .flatMap(Set::stream)
+                .map(NamedExpression::getExprId)
+                .collect(Collectors.toSet());
 
         List<NamedExpression> leftInputs = joinPlan.left().getOutput().stream()
                 .filter(r -> 
exprIds.contains(r.getExprId())).collect(Collectors.toList());
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
index 506e2d6b17..018074dcfd 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneOlapScanPartition.java
@@ -52,7 +52,6 @@ import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -98,9 +97,8 @@ public class PruneOlapScanPartition extends 
OneRewriteRuleFactory {
     private ColumnRange createColumnRange(String colName, List<Expression> 
expressionList) {
         ColumnRange result = ColumnRange.create();
         for (Expression expression : expressionList) {
-            List<SlotReference> slotReferenceList = 
expression.collect(SlotReference.class::isInstance);
-            int slotReferenceListSize = new 
HashSet<>(slotReferenceList).size();
-            if (slotReferenceListSize != 1 || 
!slotReferenceList.get(0).getName().equals(colName)) {
+            Set<SlotReference> slotReferences = 
expression.collect(SlotReference.class::isInstance);
+            if (slotReferences.size() != 1 || 
!slotReferences.iterator().next().getName().equals(colName)) {
                 continue;
             }
             if (expression instanceof Or) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneSortChildColumns.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneSortChildColumns.java
index b90ae4e80c..d7210196d1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneSortChildColumns.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PruneSortChildColumns.java
@@ -23,7 +23,6 @@ import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
 import org.apache.doris.nereids.trees.plans.logical.LogicalSort;
-import org.apache.doris.nereids.util.SlotExtractor;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -45,7 +44,7 @@ public class PruneSortChildColumns extends 
AbstractPushDownProjectRule<LogicalSo
 
     @Override
     protected Plan pushDownProject(LogicalSort<GroupPlan> sortPlan, Set<Slot> 
references) {
-        Set<Slot> sortSlots = 
SlotExtractor.extractSlot(sortPlan.getExpressions());
+        Set<Slot> sortSlots = sortPlan.getOutputSet();
         Set<Slot> required = Stream.concat(references.stream(), 
sortSlots.stream()).collect(Collectors.toSet());
         if (required.containsAll(sortPlan.child().getOutput())) {
             return sortPlan;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughAggregation.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughAggregation.java
index 6148acc178..4e8aa50398 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughAggregation.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughAggregation.java
@@ -27,7 +27,6 @@ import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
 import org.apache.doris.nereids.util.ExpressionUtils;
-import org.apache.doris.nereids.util.SlotExtractor;
 
 import com.google.common.collect.Lists;
 
@@ -77,7 +76,7 @@ public class PushPredicateThroughAggregation extends 
OneRewriteRuleFactory {
             List<Expression> pushDownPredicates = Lists.newArrayList();
             List<Expression> filterPredicates = Lists.newArrayList();
             
ExpressionUtils.extractConjunction(filter.getPredicates()).forEach(conjunct -> {
-                Set<Slot> conjunctSlots = SlotExtractor.extractSlot(conjunct);
+                Set<Slot> conjunctSlots = conjunct.getInputSlots();
                 if (groupBySlots.containsAll(conjunctSlots)) {
                     pushDownPredicates.add(conjunct);
                 } else {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughJoin.java
index 7b39929392..70e75adc98 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushPredicateThroughJoin.java
@@ -29,7 +29,6 @@ import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
 import org.apache.doris.nereids.util.ExpressionUtils;
-import org.apache.doris.nereids.util.SlotExtractor;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -92,7 +91,7 @@ public class PushPredicateThroughJoin extends 
OneRewriteRuleFactory {
             List<Expression> rightPredicates = Lists.newArrayList();
 
             for (Expression p : otherConditions) {
-                Set<Slot> slots = SlotExtractor.extractSlot(p);
+                Set<Slot> slots = p.getInputSlots();
                 if (slots.isEmpty()) {
                     leftPredicates.add(p);
                     rightPredicates.add(p);
@@ -141,8 +140,8 @@ public class PushPredicateThroughJoin extends 
OneRewriteRuleFactory {
 
         ComparisonPredicate comparison = (ComparisonPredicate) predicate;
 
-        Set<Slot> leftSlots = SlotExtractor.extractSlot(comparison.left());
-        Set<Slot> rightSlots = SlotExtractor.extractSlot(comparison.right());
+        Set<Slot> leftSlots = comparison.left().getInputSlots();
+        Set<Slot> rightSlots = comparison.right().getInputSlots();
 
         if (!(leftSlots.size() >= 1 && rightSlots.size() >= 1)) {
             return null;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/JoinEstimation.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/JoinEstimation.java
index a7c47e6ce6..161194456e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/JoinEstimation.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/JoinEstimation.java
@@ -31,7 +31,6 @@ import org.apache.doris.statistics.StatsDeriveResult;
 
 import com.google.common.base.Preconditions;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -51,9 +50,8 @@ public class JoinEstimation {
         statsDeriveResult.merge(rightStats);
         // TODO: normalize join hashConjuncts.
         List<Expression> hashJoinConjuncts = join.getHashJoinConjuncts();
-        List<Slot> leftSlot = new 
ArrayList<>(leftStats.getSlotToColumnStats().keySet());
         List<Expression> normalizedConjuncts = 
hashJoinConjuncts.stream().map(EqualTo.class::cast)
-                .map(e -> JoinUtils.swapEqualToForChildrenOrder(e, leftSlot))
+                .map(e -> JoinUtils.swapEqualToForChildrenOrder(e, 
leftStats.getSlotToColumnStats().keySet()))
                         .collect(Collectors.toList());
         long rowCount = -1;
         if (joinType.isSemiOrAntiJoin()) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java
index 0843ad5fba..2eadaa8941 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java
@@ -279,14 +279,14 @@ public class StatsCalculator extends 
DefaultPlanVisitor<StatsDeriveResult, Void>
         Map<Slot, ColumnStats> childSlotToColumnStats = 
childStats.getSlotToColumnStats();
         long resultSetCount = 1;
         for (Expression groupByExpression : groupByExpressions) {
-            List<SlotReference> slotReferences = 
groupByExpression.collect(SlotReference.class::isInstance);
+            Set<Slot> slots = groupByExpression.getInputSlots();
             // TODO: Support more complex group expr.
             //       For example:
             //              select max(col1+col3) from t1 group by col1+col3;
-            if (slotReferences.size() != 1) {
+            if (slots.size() != 1) {
                 continue;
             }
-            SlotReference slotReference = slotReferences.get(0);
+            Slot slotReference = slots.iterator().next();
             ColumnStats columnStats = 
childSlotToColumnStats.get(slotReference);
             resultSetCount *= columnStats.getNdv();
         }
@@ -308,12 +308,13 @@ public class StatsCalculator extends 
DefaultPlanVisitor<StatsDeriveResult, Void>
         StatsDeriveResult statsDeriveResult = 
groupExpression.getCopyOfChildStats(0);
         Map<Slot, ColumnStats> childColumnStats = 
statsDeriveResult.getSlotToColumnStats();
         Map<Slot, ColumnStats> columnsStats = 
projections.stream().map(projection -> {
-            List<SlotReference> slotReferences = 
projection.collect(SlotReference.class::isInstance);
-            if (slotReferences.isEmpty()) {
+            Set<Slot> slots = projection.getInputSlots();
+            if (slots.isEmpty()) {
                 return new AbstractMap.SimpleEntry<>(projection.toSlot(), 
ColumnStats.createDefaultColumnStats());
             } else {
                 // TODO: just a trick here, need to do real project on column 
stats
-                return new AbstractMap.SimpleEntry<>(projection.toSlot(), 
childColumnStats.get(slotReferences.get(0)));
+                return new AbstractMap.SimpleEntry<>(projection.toSlot(),
+                        childColumnStats.get(slots.iterator().next()));
             }
         }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
         statsDeriveResult.setSlotToColumnStats(columnsStats);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
index f8d4ca04e4..ea8158ae22 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
@@ -18,6 +18,7 @@
 package org.apache.doris.nereids.trees;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 
 import java.util.List;
 import java.util.function.Consumer;
@@ -75,7 +76,7 @@ public interface TreeNode<NODE_TYPE extends 
TreeNode<NODE_TYPE>> {
      * Collect the nodes that satisfied the predicate.
      */
     default <T> T collect(Predicate<TreeNode<NODE_TYPE>> predicate) {
-        ImmutableList.Builder<TreeNode<NODE_TYPE>> result = 
ImmutableList.builder();
+        ImmutableSet.Builder<TreeNode<NODE_TYPE>> result = 
ImmutableSet.builder();
         foreach(node -> {
             if (predicate.test(node)) {
                 result.add(node);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
index 173b363799..df35564499 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
@@ -17,6 +17,7 @@
 
 package org.apache.doris.nereids.trees.expressions;
 
+import org.apache.doris.nereids.analyzer.Unbound;
 import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.exceptions.UnboundException;
 import org.apache.doris.nereids.trees.AbstractTreeNode;
@@ -35,6 +36,7 @@ import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Abstract class for all Expression in Nereids.
@@ -126,6 +128,15 @@ public abstract class Expression extends 
AbstractTreeNode<Expression> {
         throw new RuntimeException("Do not implement uncheckedCastTo");
     }
 
+    /**
+     * Get all the input slots of the expression.
+     * <p>
+     * Note that the input slots of subquery's inner plan is not included.
+     */
+    public final Set<Slot> getInputSlots() {
+        return collect(Slot.class::isInstance);
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -143,4 +154,10 @@ public abstract class Expression extends 
AbstractTreeNode<Expression> {
         return 0;
     }
 
+    /**
+     * This expression has unbound symbols or not.
+     */
+    public boolean hasUnbound() {
+        return this.anyMatch(Unbound.class::isInstance);
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
index a4b3d67e37..d24d9b3df8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java
@@ -25,7 +25,9 @@ import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.util.TreeStringUtils;
 import org.apache.doris.statistics.StatsDeriveResult;
 
-import java.util.ArrayList;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -38,7 +40,7 @@ public abstract class AbstractPlan extends 
AbstractTreeNode<Plan> implements Pla
     protected StatsDeriveResult statsDeriveResult;
     protected final PlanType type;
     protected final Optional<GroupExpression> groupExpression;
-    protected final LogicalProperties logicalProperties;
+    protected final Supplier<LogicalProperties> logicalPropertiesSupplier;
 
     public AbstractPlan(PlanType type, Plan... children) {
         this(type, Optional.empty(), Optional.empty(), children);
@@ -54,8 +56,9 @@ public abstract class AbstractPlan extends 
AbstractTreeNode<Plan> implements Pla
         super(groupExpression, children);
         this.type = Objects.requireNonNull(type, "type can not be null");
         this.groupExpression = Objects.requireNonNull(groupExpression, 
"groupExpression can not be null");
-        LogicalProperties logicalProperties = 
optLogicalProperties.orElseGet(() -> computeLogicalProperties());
-        this.logicalProperties = Objects.requireNonNull(logicalProperties, 
"logicalProperties can not be null");
+        Objects.requireNonNull(optLogicalProperties, "logicalProperties can 
not be null");
+        this.logicalPropertiesSupplier = Suppliers.memoize(() -> 
optLogicalProperties.orElseGet(
+                this::computeLogicalProperties));
     }
 
     @Override
@@ -86,30 +89,6 @@ public abstract class AbstractPlan extends 
AbstractTreeNode<Plan> implements Pla
                 plan -> (List) ((Plan) plan).children());
     }
 
-    private void treeString(List<String> lines, int depth, List<Boolean> 
lastChildren, Plan plan) {
-        StringBuilder sb = new StringBuilder();
-        if (depth > 0) {
-            if (lastChildren.size() > 1) {
-                for (int i = 0; i < lastChildren.size() - 1; i++) {
-                    sb.append(lastChildren.get(i) ? "   " : "|  ");
-                }
-            }
-            if (lastChildren.size() > 0) {
-                Boolean last = lastChildren.get(lastChildren.size() - 1);
-                sb.append(last ? "+--" : "|--");
-            }
-        }
-        sb.append(plan.toString());
-        lines.add(sb.toString());
-
-        List<Plan> children = plan.children();
-        for (int i = 0; i < children.size(); i++) {
-            List<Boolean> newLasts = new ArrayList<>(lastChildren);
-            newLasts.add(i + 1 == children.size());
-            treeString(lines, depth + 1, newLasts, children.get(i));
-        }
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -120,17 +99,17 @@ public abstract class AbstractPlan extends 
AbstractTreeNode<Plan> implements Pla
         }
         AbstractPlan that = (AbstractPlan) o;
         return Objects.equals(statsDeriveResult, that.statsDeriveResult)
-                && Objects.equals(logicalProperties, that.logicalProperties);
+                && Objects.equals(getLogicalProperties(), 
that.getLogicalProperties());
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(statsDeriveResult, logicalProperties);
+        return Objects.hash(statsDeriveResult, getLogicalProperties());
     }
 
     @Override
     public List<Slot> getOutput() {
-        return logicalProperties.getOutput();
+        return getLogicalProperties().getOutput();
     }
 
     @Override
@@ -138,4 +117,8 @@ public abstract class AbstractPlan extends 
AbstractTreeNode<Plan> implements Pla
         return super.child(index);
     }
 
+    @Override
+    public LogicalProperties getLogicalProperties() {
+        return logicalPropertiesSupplier.get();
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
index 717f5ac347..79c50c264b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
@@ -25,8 +25,11 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
+import com.google.common.collect.ImmutableSet;
+
 import java.util.List;
 import java.util.Optional;
+import java.util.Set;
 
 /**
  * Abstract class for all plan node.
@@ -50,6 +53,10 @@ public interface Plan extends TreeNode<Plan> {
         return !(getLogicalProperties() instanceof UnboundLogicalProperties);
     }
 
+    default boolean hasUnboundExpression() {
+        return getExpressions().stream().anyMatch(Expression::hasUnbound);
+    }
+
     default boolean childrenBound() {
         return children()
                 .stream()
@@ -60,8 +67,30 @@ public interface Plan extends TreeNode<Plan> {
         throw new IllegalStateException("Not support compute logical 
properties for " + getClass().getName());
     }
 
+    /**
+     * Get output slot list of the plan.
+     */
     List<Slot> getOutput();
 
+    /**
+     * Get output slot set of the plan.
+     */
+    default Set<Slot> getOutputSet() {
+        return ImmutableSet.copyOf(getOutput());
+    }
+
+    /**
+     * Get the input slot set of the plan.
+     * The result is collected from all the expressions' input slots appearing 
in the plan node.
+     * <p>
+     * Note that the input slots of subquery's inner plan are not included.
+     */
+    default Set<Slot> getInputSlots() {
+        return getExpressions().stream()
+                .flatMap(expr -> expr.getInputSlots().stream())
+                .collect(ImmutableSet.toImmutableSet());
+    }
+
     default List<Slot> computeOutput() {
         throw new IllegalStateException("Not support compute output for " + 
getClass().getName());
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/AbstractLogicalPlan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/AbstractLogicalPlan.java
index 091f7154b6..0bf48f29c1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/AbstractLogicalPlan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/AbstractLogicalPlan.java
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.plans.logical;
 
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.LogicalProperties;
+import org.apache.doris.nereids.properties.UnboundLogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.AbstractPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -46,12 +47,18 @@ public abstract class AbstractLogicalPlan extends 
AbstractPlan implements Logica
     }
 
     @Override
-    public LogicalProperties getLogicalProperties() {
-        return logicalProperties;
+    public List<Slot> getOutput() {
+        return getLogicalProperties().getOutput();
     }
 
     @Override
-    public List<Slot> getOutput() {
-        return logicalProperties.getOutput();
+    public LogicalProperties computeLogicalProperties() {
+        boolean hasUnboundChild = 
children.stream().map(Plan::getLogicalProperties)
+                .anyMatch(UnboundLogicalProperties.class::isInstance);
+        if (hasUnboundChild || hasUnboundExpression()) {
+            return UnboundLogicalProperties.INSTANCE;
+        } else {
+            return new LogicalProperties(this::computeOutput);
+        }
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
index b9aa420f06..f847bdd5d6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAggregate.java
@@ -180,7 +180,8 @@ public class LogicalAggregate<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHIL
     @Override
     public LogicalAggregate<Plan> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
         return new LogicalAggregate<>(groupByExpressions, outputExpressions,
-                disassembled, normalized, aggPhase, groupExpression, 
Optional.of(logicalProperties), children.get(0));
+                disassembled, normalized, aggPhase, groupExpression, 
Optional.of(getLogicalProperties()),
+                children.get(0));
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalApply.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalApply.java
index bdc2e50580..a0ea3504d2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalApply.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalApply.java
@@ -161,7 +161,7 @@ public class LogicalApply<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalApply<>(groupExpression, 
Optional.of(logicalProperties),
+        return new LogicalApply<>(groupExpression, 
Optional.of(getLogicalProperties()),
                 correlationSlot, subqueryExpr, correlationFilter, left(), 
right());
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
index b25980c193..f4063eba53 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java
@@ -98,7 +98,7 @@ public class LogicalAssertNumRows<CHILD_TYPE extends Plan> 
extends LogicalUnary<
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
         return new LogicalAssertNumRows<>(assertNumRowsElement,
-                groupExpression, Optional.of(logicalProperties), child());
+                groupExpression, Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
index 579c07ba7c..827c3c9020 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
@@ -19,7 +19,6 @@ package org.apache.doris.nereids.trees.plans.logical;
 
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.LogicalProperties;
-import org.apache.doris.nereids.properties.UnboundLogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.BinaryPlan;
 import org.apache.doris.nereids.trees.plans.Plan;
@@ -53,13 +52,4 @@ public abstract class LogicalBinary<
     }
 
     public abstract List<Slot> computeOutput();
-
-    @Override
-    public final LogicalProperties computeLogicalProperties() {
-        if (left().getLogicalProperties() instanceof UnboundLogicalProperties
-                || right().getLogicalProperties() instanceof 
UnboundLogicalProperties) {
-            return new UnboundLogicalProperties();
-        }
-        return new LogicalProperties(() -> computeOutput());
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
index b9ceb07efe..641730d5ba 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
@@ -101,7 +101,7 @@ public class LogicalFilter<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_T
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalFilter<>(predicates, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalFilter<>(predicates, groupExpression, 
Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalHaving.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalHaving.java
index 4e49c5330b..11cc4f389b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalHaving.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalHaving.java
@@ -75,7 +75,7 @@ public class LogicalHaving<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_T
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalHaving<>(predicates, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalHaving<>(predicates, groupExpression, 
Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
index 7963a24ab8..12052cbeb5 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
@@ -32,6 +32,7 @@ import org.apache.doris.nereids.util.Utils;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
 
 import java.util.List;
 import java.util.Objects;
@@ -211,7 +212,10 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
 
     @Override
     public List<Expression> getExpressions() {
-        return 
otherJoinCondition.<List<Expression>>map(ImmutableList::of).orElseGet(ImmutableList::of);
+        Builder<Expression> builder = new Builder<Expression>()
+                .addAll(hashJoinConjuncts);
+        otherJoinCondition.ifPresent(builder::add);
+        return builder.build();
     }
 
     public JoinReorderContext getJoinReorderContext() {
@@ -228,7 +232,7 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, 
RIGHT_CHILD_TYPE extends
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
         return new LogicalJoin<>(joinType, hashJoinConjuncts, 
otherJoinCondition, groupExpression,
-                Optional.of(logicalProperties), left(), right(), 
joinReorderContext);
+                Optional.of(getLogicalProperties()), left(), right(), 
joinReorderContext);
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
index 0d6f061184..56a0301735 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
@@ -45,9 +45,4 @@ public abstract class LogicalLeaf extends AbstractLogicalPlan 
implements LeafPla
     }
 
     public abstract List<Slot> computeOutput();
-
-    @Override
-    public LogicalProperties computeLogicalProperties() {
-        return new LogicalProperties(() -> computeOutput());
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLimit.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLimit.java
index c5b80b75e0..b1460ab43b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLimit.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLimit.java
@@ -107,7 +107,7 @@ public class LogicalLimit<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TY
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalLimit<>(limit, offset, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalLimit<>(limit, offset, groupExpression, 
Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
index 5dfac9febb..67436166f5 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
@@ -103,7 +103,7 @@ public class LogicalOlapScan extends LogicalRelation {
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalOlapScan(table, qualifier, groupExpression, 
Optional.of(logicalProperties),
+        return new LogicalOlapScan(table, qualifier, groupExpression, 
Optional.of(getLogicalProperties()),
                 selectedPartitionIds, partitionPruned);
     }
 
@@ -114,7 +114,7 @@ public class LogicalOlapScan extends LogicalRelation {
     }
 
     public LogicalOlapScan withSelectedPartitionId(List<Long> 
selectedPartitionId) {
-        return new LogicalOlapScan(table, qualifier, Optional.empty(), 
Optional.of(logicalProperties),
+        return new LogicalOlapScan(table, qualifier, Optional.empty(), 
Optional.of(logicalPropertiesSupplier.get()),
                 selectedPartitionId, true);
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
index 738c2a53e1..afaa60723a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
@@ -116,7 +116,7 @@ public class LogicalProject<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHILD_
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalProject<>(projects, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalProject<>(projects, groupExpression, 
Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
index df9a2e8fbf..401907811a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java
@@ -88,7 +88,7 @@ public class LogicalSelectHint<CHILD_TYPE extends Plan> 
extends LogicalUnary<CHI
 
     @Override
     public LogicalSelectHint<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new LogicalSelectHint<>(hints, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalSelectHint<>(hints, groupExpression, 
Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java
index 4a7f5b51b1..4147adc238 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java
@@ -111,7 +111,7 @@ public class LogicalSort<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYP
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalSort<>(orderKeys, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalSort<>(orderKeys, groupExpression, 
Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
index fc71a8fedc..0f357e4ebc 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java
@@ -106,7 +106,7 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> 
extends LogicalUnary<
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalSubQueryAlias<>(alias, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalSubQueryAlias<>(alias, groupExpression, 
Optional.of(getLogicalProperties()), child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalTopN.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalTopN.java
index e82ccb9c8c..cc60c1bef7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalTopN.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalTopN.java
@@ -122,7 +122,8 @@ public class LogicalTopN<CHILD_TYPE extends Plan> extends 
LogicalUnary<CHILD_TYP
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new LogicalTopN<>(orderKeys, limit, offset, groupExpression, 
Optional.of(logicalProperties), child());
+        return new LogicalTopN<>(orderKeys, limit, offset, groupExpression, 
Optional.of(getLogicalProperties()),
+                child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
index 849dfb337e..fd0f4cc723 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
@@ -19,7 +19,6 @@ package org.apache.doris.nereids.trees.plans.logical;
 
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.LogicalProperties;
-import org.apache.doris.nereids.properties.UnboundLogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
@@ -49,12 +48,4 @@ public abstract class LogicalUnary<CHILD_TYPE extends Plan>
     }
 
     public abstract List<Slot> computeOutput();
-
-    @Override
-    public LogicalProperties computeLogicalProperties() {
-        if (child().getLogicalProperties() instanceof 
UnboundLogicalProperties) {
-            return new UnboundLogicalProperties();
-        }
-        return new LogicalProperties(() -> computeOutput());
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java
index 26b86d6cc8..b097cc5810 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalJoin.java
@@ -27,7 +27,7 @@ import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.algebra.Join;
 import org.apache.doris.nereids.util.ExpressionUtils;
 
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
 
 import java.util.List;
 import java.util.Objects;
@@ -92,7 +92,10 @@ public abstract class AbstractPhysicalJoin<
 
     @Override
     public List<Expression> getExpressions() {
-        return 
otherJoinCondition.<List<Expression>>map(ImmutableList::of).orElseGet(ImmutableList::of);
+        Builder<Expression> builder = new Builder<Expression>()
+                .addAll(hashJoinConjuncts);
+        otherJoinCondition.ifPresent(builder::add);
+        return builder.build();
     }
 
     // TODO:
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java
index d31c643bba..e28d0ecdef 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java
@@ -59,12 +59,6 @@ public abstract class AbstractPhysicalPlan extends 
AbstractPlan implements Physi
         this.physicalProperties = physicalProperties;
     }
 
-    @Override
-    public LogicalProperties getLogicalProperties() {
-        return logicalProperties;
-    }
-
-    @Override
     public PhysicalProperties getPhysicalProperties() {
         return physicalProperties;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java
index 6c807271e2..51b378bab7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java
@@ -168,13 +168,13 @@ public class PhysicalAggregate<CHILD_TYPE extends Plan> 
extends PhysicalUnary<CH
     public PhysicalAggregate<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
         return new PhysicalAggregate<>(groupByExpressions, outputExpressions, 
partitionExpressions, aggPhase,
-                usingStream, logicalProperties, children.get(0));
+                usingStream, getLogicalProperties(), children.get(0));
     }
 
     @Override
     public PhysicalAggregate<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
         return new PhysicalAggregate<>(groupByExpressions, outputExpressions, 
partitionExpressions, aggPhase,
-                usingStream, groupExpression, logicalProperties, child());
+                usingStream, groupExpression, getLogicalProperties(), child());
     }
 
     @Override
@@ -186,6 +186,6 @@ public class PhysicalAggregate<CHILD_TYPE extends Plan> 
extends PhysicalUnary<CH
     @Override
     public PhysicalAggregate<CHILD_TYPE> 
withPhysicalProperties(PhysicalProperties physicalProperties) {
         return new PhysicalAggregate<>(groupByExpressions, outputExpressions, 
partitionExpressions, aggPhase,
-                usingStream, Optional.empty(), logicalProperties, 
physicalProperties, child());
+                usingStream, Optional.empty(), getLogicalProperties(), 
physicalProperties, child());
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAssertNumRows.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAssertNumRows.java
index af13b30784..2ac46d9f10 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAssertNumRows.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAssertNumRows.java
@@ -101,24 +101,24 @@ public class PhysicalAssertNumRows<CHILD_TYPE extends 
Plan> extends PhysicalUnar
     @Override
     public PhysicalAssertNumRows<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new PhysicalAssertNumRows<>(assertNumRowsElement, 
logicalProperties, children.get(0));
+        return new PhysicalAssertNumRows<>(assertNumRowsElement, 
getLogicalProperties(), children.get(0));
     }
 
     @Override
     public PhysicalAssertNumRows<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
         return new PhysicalAssertNumRows<>(assertNumRowsElement, 
groupExpression,
-                logicalProperties, physicalProperties, child());
+                getLogicalProperties(), physicalProperties, child());
     }
 
     @Override
     public PhysicalAssertNumRows<CHILD_TYPE> 
withLogicalProperties(Optional<LogicalProperties> logicalProperties) {
         return new PhysicalAssertNumRows<>(assertNumRowsElement, 
Optional.empty(),
-                logicalProperties.get(), physicalProperties, child());
+                logicalProperties.get(), getPhysicalProperties(), child());
     }
 
     @Override
     public PhysicalAssertNumRows<CHILD_TYPE> 
withPhysicalProperties(PhysicalProperties physicalProperties) {
         return new PhysicalAssertNumRows<>(assertNumRowsElement, 
Optional.empty(),
-                logicalProperties, physicalProperties, child());
+                getLogicalProperties(), physicalProperties, child());
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalDistribute.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalDistribute.java
index a27ab21888..2e35c25d31 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalDistribute.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalDistribute.java
@@ -81,12 +81,12 @@ public class PhysicalDistribute<CHILD_TYPE extends Plan> 
extends PhysicalUnary<C
     public PhysicalDistribute<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
         return new PhysicalDistribute<>(distributionSpec, Optional.empty(),
-            logicalProperties, children.get(0));
+                getLogicalProperties(), children.get(0));
     }
 
     @Override
     public PhysicalDistribute<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new PhysicalDistribute<>(distributionSpec, groupExpression, 
logicalProperties, child());
+        return new PhysicalDistribute<>(distributionSpec, groupExpression, 
getLogicalProperties(), child());
     }
 
     @Override
@@ -98,6 +98,6 @@ public class PhysicalDistribute<CHILD_TYPE extends Plan> 
extends PhysicalUnary<C
     @Override
     public PhysicalDistribute<CHILD_TYPE> 
withPhysicalProperties(PhysicalProperties physicalProperties) {
         return new PhysicalDistribute<>(distributionSpec, Optional.empty(),
-            logicalProperties, physicalProperties, child());
+                getLogicalProperties(), physicalProperties, child());
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
index 39c8dd5f50..56ec49cdbc 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
@@ -98,12 +98,12 @@ public class PhysicalFilter<CHILD_TYPE extends Plan> 
extends PhysicalUnary<CHILD
     @Override
     public PhysicalFilter<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new PhysicalFilter<>(predicates, logicalProperties, 
children.get(0));
+        return new PhysicalFilter<>(predicates, getLogicalProperties(), 
children.get(0));
     }
 
     @Override
     public PhysicalFilter<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new PhysicalFilter<>(predicates, groupExpression, 
logicalProperties, child());
+        return new PhysicalFilter<>(predicates, groupExpression, 
getLogicalProperties(), child());
     }
 
     @Override
@@ -113,6 +113,6 @@ public class PhysicalFilter<CHILD_TYPE extends Plan> 
extends PhysicalUnary<CHILD
 
     @Override
     public PhysicalFilter<CHILD_TYPE> 
withPhysicalProperties(PhysicalProperties physicalProperties) {
-        return new PhysicalFilter<>(predicates, Optional.empty(), 
logicalProperties, physicalProperties, child());
+        return new PhysicalFilter<>(predicates, Optional.empty(), 
getLogicalProperties(), physicalProperties, child());
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
index 0e6c00a004..61aecafcd2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
@@ -93,14 +93,14 @@ public class PhysicalHashJoin<
     public PhysicalHashJoin<Plan, Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 2);
         return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, 
otherJoinCondition,
-                logicalProperties, children.get(0), children.get(1));
+                getLogicalProperties(), children.get(0), children.get(1));
     }
 
     @Override
     public PhysicalHashJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> 
withGroupExpression(
             Optional<GroupExpression> groupExpression) {
         return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, 
otherJoinCondition,
-                groupExpression, logicalProperties, left(), right());
+                groupExpression, getLogicalProperties(), left(), right());
     }
 
     @Override
@@ -114,6 +114,6 @@ public class PhysicalHashJoin<
     public PhysicalHashJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> 
withPhysicalProperties(
             PhysicalProperties physicalProperties) {
         return new PhysicalHashJoin<>(joinType, hashJoinConjuncts, 
otherJoinCondition,
-                Optional.empty(), logicalProperties, physicalProperties, 
left(), right());
+                Optional.empty(), getLogicalProperties(), physicalProperties, 
left(), right());
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
index 33ad8120c7..fb800f6d71 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLimit.java
@@ -89,7 +89,7 @@ public class PhysicalLimit<CHILD_TYPE extends Plan> extends 
PhysicalUnary<CHILD_
     @Override
     public Plan withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new PhysicalLimit<>(limit, offset, logicalProperties, 
children.get(0));
+        return new PhysicalLimit<>(limit, offset, getLogicalProperties(), 
children.get(0));
     }
 
     @Override
@@ -102,7 +102,7 @@ public class PhysicalLimit<CHILD_TYPE extends Plan> extends 
PhysicalUnary<CHILD_
 
     @Override
     public PhysicalLimit<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new PhysicalLimit<>(limit, offset, groupExpression, 
logicalProperties, child());
+        return new PhysicalLimit<>(limit, offset, groupExpression, 
getLogicalProperties(), child());
     }
 
     @Override
@@ -112,7 +112,7 @@ public class PhysicalLimit<CHILD_TYPE extends Plan> extends 
PhysicalUnary<CHILD_
 
     @Override
     public PhysicalLimit<CHILD_TYPE> withPhysicalProperties(PhysicalProperties 
physicalProperties) {
-        return new PhysicalLimit<>(limit, offset, groupExpression, 
logicalProperties, physicalProperties, child());
+        return new PhysicalLimit<>(limit, offset, groupExpression, 
getLogicalProperties(), physicalProperties, child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLocalQuickSort.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLocalQuickSort.java
index 97da85c2c4..fd01e99c51 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLocalQuickSort.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLocalQuickSort.java
@@ -73,12 +73,12 @@ public class PhysicalLocalQuickSort<CHILD_TYPE extends 
Plan> extends AbstractPhy
     @Override
     public PhysicalLocalQuickSort<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new PhysicalLocalQuickSort<>(orderKeys, logicalProperties, 
children.get(0));
+        return new PhysicalLocalQuickSort<>(orderKeys, getLogicalProperties(), 
children.get(0));
     }
 
     @Override
     public PhysicalLocalQuickSort<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new PhysicalLocalQuickSort<>(orderKeys, groupExpression, 
logicalProperties, child());
+        return new PhysicalLocalQuickSort<>(orderKeys, groupExpression, 
getLogicalProperties(), child());
     }
 
     @Override
@@ -89,7 +89,7 @@ public class PhysicalLocalQuickSort<CHILD_TYPE extends Plan> 
extends AbstractPhy
     @Override
     public PhysicalLocalQuickSort<CHILD_TYPE> 
withPhysicalProperties(PhysicalProperties physicalProperties) {
         return new PhysicalLocalQuickSort<>(orderKeys, Optional.empty(),
-                logicalProperties, physicalProperties, child());
+                getLogicalProperties(), physicalProperties, child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java
index 0977394343..01d847c208 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java
@@ -96,14 +96,14 @@ public class PhysicalNestedLoopJoin<
     public PhysicalNestedLoopJoin<Plan, Plan> withChildren(List<Plan> 
children) {
         Preconditions.checkArgument(children.size() == 2);
         return new PhysicalNestedLoopJoin<>(joinType,
-                hashJoinConjuncts, otherJoinCondition, logicalProperties, 
children.get(0), children.get(1));
+                hashJoinConjuncts, otherJoinCondition, getLogicalProperties(), 
children.get(0), children.get(1));
     }
 
     @Override
     public PhysicalNestedLoopJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> 
withGroupExpression(
             Optional<GroupExpression> groupExpression) {
         return new PhysicalNestedLoopJoin<>(joinType,
-                hashJoinConjuncts, otherJoinCondition, groupExpression, 
logicalProperties, left(), right());
+                hashJoinConjuncts, otherJoinCondition, groupExpression, 
getLogicalProperties(), left(), right());
     }
 
     @Override
@@ -119,6 +119,6 @@ public class PhysicalNestedLoopJoin<
             PhysicalProperties physicalProperties) {
         return new PhysicalNestedLoopJoin<>(joinType,
                 hashJoinConjuncts, otherJoinCondition, Optional.empty(),
-                logicalProperties, physicalProperties, left(), right());
+                getLogicalProperties(), physicalProperties, left(), right());
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
index 0902d5810f..959c0275b1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
@@ -126,7 +126,7 @@ public class PhysicalOlapScan extends PhysicalRelation {
     @Override
     public PhysicalOlapScan withGroupExpression(Optional<GroupExpression> 
groupExpression) {
         return new PhysicalOlapScan(olapTable, qualifier, selectedIndexId, 
selectedTabletIds, selectedPartitionIds,
-                distributionSpec, groupExpression, logicalProperties);
+                distributionSpec, groupExpression, getLogicalProperties());
     }
 
     @Override
@@ -138,6 +138,6 @@ public class PhysicalOlapScan extends PhysicalRelation {
     @Override
     public PhysicalOlapScan withPhysicalProperties(PhysicalProperties 
physicalProperties) {
         return new PhysicalOlapScan(olapTable, qualifier, selectedIndexId, 
selectedTabletIds, selectedPartitionIds,
-                distributionSpec, Optional.empty(), logicalProperties, 
physicalProperties);
+                distributionSpec, Optional.empty(), getLogicalProperties(), 
physicalProperties);
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
index a65e46e282..e4287e4710 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
@@ -98,12 +98,12 @@ public class PhysicalProject<CHILD_TYPE extends Plan> 
extends PhysicalUnary<CHIL
     @Override
     public PhysicalProject<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new PhysicalProject<>(projects, logicalProperties, 
children.get(0));
+        return new PhysicalProject<>(projects, getLogicalProperties(), 
children.get(0));
     }
 
     @Override
     public PhysicalProject<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new PhysicalProject<>(projects, groupExpression, 
logicalProperties, child());
+        return new PhysicalProject<>(projects, groupExpression, 
getLogicalProperties(), child());
     }
 
     @Override
@@ -113,6 +113,6 @@ public class PhysicalProject<CHILD_TYPE extends Plan> 
extends PhysicalUnary<CHIL
 
     @Override
     public PhysicalProject<CHILD_TYPE> 
withPhysicalProperties(PhysicalProperties physicalProperties) {
-        return new PhysicalProject<>(projects, Optional.empty(), 
logicalProperties, physicalProperties, child());
+        return new PhysicalProject<>(projects, Optional.empty(), 
getLogicalProperties(), physicalProperties, child());
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
index 713b658c8d..c0e77047e6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalQuickSort.java
@@ -68,12 +68,12 @@ public class PhysicalQuickSort<CHILD_TYPE extends Plan> 
extends AbstractPhysical
     @Override
     public PhysicalQuickSort<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new PhysicalQuickSort<>(orderKeys, logicalProperties, 
children.get(0));
+        return new PhysicalQuickSort<>(orderKeys, getLogicalProperties(), 
children.get(0));
     }
 
     @Override
     public PhysicalQuickSort<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new PhysicalQuickSort<>(orderKeys, groupExpression, 
logicalProperties, child());
+        return new PhysicalQuickSort<>(orderKeys, groupExpression, 
getLogicalProperties(), child());
     }
 
     @Override
@@ -83,7 +83,8 @@ public class PhysicalQuickSort<CHILD_TYPE extends Plan> 
extends AbstractPhysical
 
     @Override
     public PhysicalQuickSort<CHILD_TYPE> 
withPhysicalProperties(PhysicalProperties physicalProperties) {
-        return new PhysicalQuickSort<>(orderKeys, Optional.empty(), 
logicalProperties, physicalProperties, child());
+        return new PhysicalQuickSort<>(orderKeys, Optional.empty(), 
getLogicalProperties(), physicalProperties,
+                child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalTopN.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalTopN.java
index 8cd41a6624..8caacfc426 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalTopN.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalTopN.java
@@ -115,12 +115,12 @@ public class PhysicalTopN<CHILD_TYPE extends Plan> 
extends AbstractPhysicalSort<
     @Override
     public PhysicalTopN<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new PhysicalTopN<>(orderKeys, limit, offset, logicalProperties, 
children.get(0));
+        return new PhysicalTopN<>(orderKeys, limit, offset, 
getLogicalProperties(), children.get(0));
     }
 
     @Override
     public PhysicalTopN<CHILD_TYPE> 
withGroupExpression(Optional<GroupExpression> groupExpression) {
-        return new PhysicalTopN<>(orderKeys, limit, offset, groupExpression, 
logicalProperties, child());
+        return new PhysicalTopN<>(orderKeys, limit, offset, groupExpression, 
getLogicalProperties(), child());
     }
 
     @Override
@@ -131,7 +131,7 @@ public class PhysicalTopN<CHILD_TYPE extends Plan> extends 
AbstractPhysicalSort<
     @Override
     public PhysicalTopN<CHILD_TYPE> withPhysicalProperties(PhysicalProperties 
physicalProperties) {
         return new PhysicalTopN<>(orderKeys, limit, offset, Optional.empty(),
-                logicalProperties, physicalProperties, child());
+                getLogicalProperties(), physicalProperties, child());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
index a59cc989fb..7f22a4b2fb 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java
@@ -21,7 +21,6 @@ import org.apache.doris.nereids.trees.expressions.And;
 import org.apache.doris.nereids.trees.expressions.CompoundPredicate;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Or;
-import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
 
 import com.google.common.base.Preconditions;
@@ -121,18 +120,4 @@ public class ExpressionUtils {
                 .reduce(type == And.class ? And::new : Or::new)
                 .orElse(new BooleanLiteral(type == And.class));
     }
-
-    /**
-     * Check whether lhs and rhs (both are List of SlotReference) are 
intersecting.
-     */
-    public static boolean isIntersecting(List<SlotReference> lhs, 
List<SlotReference> rhs) {
-        for (SlotReference lSlot : lhs) {
-            for (SlotReference rSlot : rhs) {
-                if (lSlot.equals(rSlot)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
index 584058f35b..b17a176148 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
@@ -25,7 +25,6 @@ import 
org.apache.doris.nereids.properties.DistributionSpecReplicated;
 import org.apache.doris.nereids.trees.expressions.EqualTo;
 import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.plans.JoinType;
@@ -38,6 +37,7 @@ import 
org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
 import org.apache.doris.qe.ConnectContext;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
 import java.util.List;
@@ -67,12 +67,13 @@ public class JoinUtils {
             rightExprIds = 
right.stream().map(SlotReference::getExprId).collect(Collectors.toSet());
         }
 
-        boolean isCoveredByLeftSlots(List<SlotReference> slots) {
-            return slots.stream().map(SlotReference::getExprId)
+        boolean isCoveredByLeftSlots(Set<SlotReference> slots) {
+            return slots.stream()
+                    .map(SlotReference::getExprId)
                     .allMatch(leftExprIds::contains);
         }
 
-        boolean isCoveredByRightSlots(List<SlotReference> slots) {
+        boolean isCoveredByRightSlots(Set<SlotReference> slots) {
             return slots.stream()
                     .map(SlotReference::getExprId)
                     .allMatch(rightExprIds::contains);
@@ -89,12 +90,12 @@ public class JoinUtils {
          * @return true if the equal can be used as hash join condition
          */
         boolean isHashJoinCondition(EqualTo equalTo) {
-            List<SlotReference> equalLeft = 
equalTo.left().collect(SlotReference.class::isInstance);
+            Set<SlotReference> equalLeft = 
equalTo.left().collect(SlotReference.class::isInstance);
             if (equalLeft.isEmpty()) {
                 return false;
             }
 
-            List<SlotReference> equalRight = 
equalTo.right().collect(SlotReference.class::isInstance);
+            Set<SlotReference> equalRight = 
equalTo.right().collect(SlotReference.class::isInstance);
             if (equalRight.isEmpty()) {
                 return false;
             }
@@ -134,19 +135,14 @@ public class JoinUtils {
      */
     public static Pair<List<Expression>, List<Expression>> 
extractExpressionForHashTable(List<SlotReference> leftSlots,
             List<SlotReference> rightSlots, List<Expression> onConditions) {
-
-        Pair<List<Expression>, List<Expression>> pair = 
Pair.of(Lists.newArrayList(), Lists.newArrayList());
         JoinSlotCoverageChecker checker = new 
JoinSlotCoverageChecker(leftSlots, rightSlots);
         Map<Boolean, List<Expression>> mapper = onConditions.stream()
                 .collect(Collectors.groupingBy(
                         expr -> (expr instanceof EqualTo) && 
checker.isHashJoinCondition((EqualTo) expr)));
-        if (mapper.containsKey(true)) {
-            pair.first = mapper.get(true);
-        }
-        if (mapper.containsKey(false)) {
-            pair.second = mapper.get(false);
-        }
-        return pair;
+        return Pair.of(
+                mapper.getOrDefault(true, ImmutableList.of()),
+                mapper.getOrDefault(false, ImmutableList.of())
+        );
     }
 
     /**
@@ -165,8 +161,8 @@ public class JoinUtils {
         JoinSlotCoverageChecker checker = new 
JoinSlotCoverageChecker(leftSlots, rightSlots);
 
         for (EqualTo equalTo : equalToList) {
-            List<SlotReference> leftOnSlots = 
equalTo.left().collect(SlotReference.class::isInstance);
-            List<SlotReference> rightOnSlots = 
equalTo.right().collect(SlotReference.class::isInstance);
+            Set<SlotReference> leftOnSlots = 
equalTo.left().collect(SlotReference.class::isInstance);
+            Set<SlotReference> rightOnSlots = 
equalTo.right().collect(SlotReference.class::isInstance);
             List<ExprId> leftOnSlotsExprId = leftOnSlots.stream()
                     
.map(SlotReference::getExprId).collect(Collectors.toList());
             List<ExprId> rightOnSlotsExprId = rightOnSlots.stream()
@@ -201,13 +197,11 @@ public class JoinUtils {
      * The left child of origin predicate is t2.id and the right child of 
origin predicate is t1.id.
      * In this situation, the children of predicate need to be swap => 
t1.id=t2.id.
      */
-    public static Expression swapEqualToForChildrenOrder(EqualTo equalTo, 
List<Slot> leftOutput) {
-        Set<ExprId> leftSlots = 
SlotExtractor.extractSlot(equalTo.left()).stream()
-                .map(NamedExpression::getExprId).collect(Collectors.toSet());
-        if 
(leftOutput.stream().map(NamedExpression::getExprId).collect(Collectors.toSet()).containsAll(leftSlots))
 {
+    public static Expression swapEqualToForChildrenOrder(EqualTo equalTo, 
Set<Slot> leftOutput) {
+        if (leftOutput.containsAll(equalTo.left().getInputSlots())) {
             return equalTo;
         } else {
-            return new EqualTo(equalTo.right(), equalTo.left());
+            return equalTo.commute();
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/SlotExtractor.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/SlotExtractor.java
deleted file mode 100644
index ac1f7b611e..0000000000
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/SlotExtractor.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "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
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-package org.apache.doris.nereids.util;
-
-import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.Slot;
-import org.apache.doris.nereids.trees.expressions.SlotReference;
-import 
org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionVisitor;
-
-import com.google.common.collect.Sets;
-
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * Extracts the SlotReference contained in the expression.
- */
-public class SlotExtractor {
-    private static final DefaultExpressionVisitor<Void, Set<Slot>> 
SLOT_COLLECTOR
-            = new DefaultExpressionVisitor<Void, Set<Slot>>() {
-                @Override
-                public Void visitSlotReference(SlotReference slotReference, 
Set<Slot> context) {
-                    context.add(slotReference);
-                    return null;
-                }
-            };
-
-    /**
-     * extract slot reference.
-     */
-    public static Set<Slot> extractSlot(Collection<Expression> expressions) {
-        Set<Slot> slots = Sets.newHashSet();
-        for (Expression expression : expressions) {
-            extractSlot(expression, slots);
-        }
-        return slots;
-    }
-
-    /**
-     * extract slot reference.
-     */
-    public static Set<Slot> extractSlot(Expression... expressions) {
-        Set<Slot> slots = Sets.newHashSet();
-        for (Expression expression : expressions) {
-            extractSlot(expression, slots);
-        }
-        return slots;
-    }
-
-    private static void extractSlot(Expression expression, Set<Slot> slots) {
-        expression.accept(SLOT_COLLECTOR, slots);
-    }
-}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java
index ad6f445a1b..bfa24ec51f 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java
@@ -115,7 +115,7 @@ public class RewriteTopDownJobTest {
 
         @Override
         public Plan withGroupExpression(Optional<GroupExpression> 
groupExpression) {
-            return new LogicalBoundRelation(table, qualifier, groupExpression, 
Optional.of(logicalProperties));
+            return new LogicalBoundRelation(table, qualifier, groupExpression, 
Optional.of(getLogicalProperties()));
         }
 
         @Override


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to