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 7c950c7cd5 [feature](Nereids) support cross join in Nereids (#11502)
7c950c7cd5 is described below

commit 7c950c7cd54e4eda77d155a737597b70ea329dd7
Author: morrySnow <101034200+morrys...@users.noreply.github.com>
AuthorDate: Mon Aug 8 22:14:27 2022 +0800

    [feature](Nereids) support cross join in Nereids (#11502)
    
    support cross join in Nereids
    
    1. add PhysicalNestedLoopJoin
    2. Translate PhysicalNestedLoopJoin to CrossJoinNode in 
PhysicalPlanTranslator
---
 fe/check/checkstyle/import-control.xml             |  1 +
 .../apache/doris/nereids/cost/CostCalculator.java  | 28 +++++++++
 .../glue/translator/PhysicalPlanTranslator.java    | 30 ++++++++-
 .../doris/nereids/pattern/PatternDescriptor.java   |  4 ++
 .../properties/ChildOutputPropertyDeriver.java     | 35 +++++++++++
 .../nereids/properties/RequestPropertyDeriver.java | 26 ++++++++
 .../org/apache/doris/nereids/rules/RuleSet.java    |  2 +
 .../org/apache/doris/nereids/rules/RuleType.java   |  1 +
 .../implementation/LogicalJoinToHashJoin.java      |  5 +-
 ...hJoin.java => LogicalJoinToNestedLoopJoin.java} | 23 ++++---
 .../apache/doris/nereids/stats/JoinEstimation.java | 11 +++-
 .../doris/nereids/stats/StatsCalculator.java       | 24 ++++---
 .../org/apache/doris/nereids/trees/TreeNode.java   |  3 +-
 .../apache/doris/nereids/trees/plans/PlanType.java |  1 +
 .../trees/plans/{ => algebra}/Aggregate.java       |  2 +-
 .../nereids/trees/plans/{ => algebra}/Filter.java  |  2 +-
 .../trees/plans/{Filter.java => algebra/Join.java} | 13 ++--
 .../nereids/trees/plans/{ => algebra}/Limit.java   |  2 +-
 .../nereids/trees/plans/{ => algebra}/Project.java |  2 +-
 .../nereids/trees/plans/{ => algebra}/Scan.java    |  2 +-
 .../trees/plans/logical/LogicalAggregate.java      |  2 +-
 .../nereids/trees/plans/logical/LogicalFilter.java |  2 +-
 .../nereids/trees/plans/logical/LogicalJoin.java   |  3 +-
 .../nereids/trees/plans/logical/LogicalLimit.java  |  2 +-
 .../trees/plans/logical/LogicalProject.java        |  2 +-
 .../trees/plans/logical/LogicalRelation.java       |  2 +-
 .../trees/plans/physical/PhysicalAggregate.java    |  2 +-
 .../trees/plans/physical/PhysicalFilter.java       |  2 +-
 .../trees/plans/physical/PhysicalHashJoin.java     | 44 +------------
 .../{PhysicalHashJoin.java => PhysicalJoin.java}   | 65 ++++---------------
 .../trees/plans/physical/PhysicalLimit.java        |  2 +-
 ...alHashJoin.java => PhysicalNestedLoopJoin.java} | 73 ++++++----------------
 .../trees/plans/physical/PhysicalProject.java      |  2 +-
 .../trees/plans/physical/PhysicalRelation.java     |  2 +-
 .../nereids/trees/plans/visitor/PlanVisitor.java   |  5 ++
 .../org/apache/doris/nereids/util/JoinUtils.java   | 17 +++--
 .../doris/nereids/stats/StatsCalculatorTest.java   | 13 ++--
 .../doris/nereids/trees/plans/FakeJoin.java}       | 29 +++++----
 regression-test/data/nereids_syntax_p0/join.out    | 11 ++++
 .../suites/nereids_syntax_p0/join.groovy           |  4 ++
 40 files changed, 283 insertions(+), 218 deletions(-)

diff --git a/fe/check/checkstyle/import-control.xml 
b/fe/check/checkstyle/import-control.xml
index 21be19ab30..5173416552 100644
--- a/fe/check/checkstyle/import-control.xml
+++ b/fe/check/checkstyle/import-control.xml
@@ -24,6 +24,7 @@ under the License.
 
 <import-control pkg="org.apache.doris" strategyOnMismatch="allowed">
     <disallow pkg="com.clearspring.analytics.util" />
+    <disallow pkg="com.alibaba.google" />
     <subpackage name="nereids">
         <allow pkg="org.junit.jupiter"/>
         <disallow pkg="org.junit"/>
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java
index 055232bda1..6bf577cdf3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostCalculator.java
@@ -25,6 +25,7 @@ import 
org.apache.doris.nereids.trees.plans.physical.PhysicalAggregate;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalDistribution;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
@@ -133,5 +134,32 @@ public class CostCalculator {
                     0);
         }
 
+        @Override
+        public CostEstimate 
visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
+                PlanContext context) {
+            // TODO: copy from physicalHashJoin, should update according to 
physical nested loop join properties.
+            Preconditions.checkState(context.getGroupExpression().arity() == 
2);
+            Preconditions.checkState(context.getChildrenStats().size() == 2);
+
+            StatsDeriveResult leftStatistics = context.getChildStatistics(0);
+            StatsDeriveResult rightStatistics = context.getChildStatistics(1);
+            List<Id> leftIds = context.getChildOutputIds(0);
+            List<Id> rightIds = context.getChildOutputIds(1);
+
+            // TODO: handle some case
+            // handle cross join, onClause is empty .....
+            if (nestedLoopJoin.getJoinType().isCrossJoin()) {
+                return new CostEstimate(
+                        leftStatistics.computeColumnSize(leftIds) + 
rightStatistics.computeColumnSize(rightIds),
+                        rightStatistics.computeColumnSize(rightIds),
+                        0);
+            }
+
+            // TODO: network 0?
+            return new CostEstimate(
+                    (leftStatistics.computeColumnSize(leftIds) + 
rightStatistics.computeColumnSize(rightIds)) / 2,
+                    rightStatistics.computeColumnSize(rightIds),
+                    0);
+        }
     }
 }
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 eb61c3fe9c..9270d51a41 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
@@ -47,14 +47,17 @@ import 
org.apache.doris.nereids.trees.plans.physical.PhysicalFilter;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
 import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
 import org.apache.doris.nereids.util.ExpressionUtils;
+import org.apache.doris.nereids.util.JoinUtils;
 import org.apache.doris.nereids.util.SlotExtractor;
 import org.apache.doris.nereids.util.Utils;
 import org.apache.doris.planner.AggregationNode;
+import org.apache.doris.planner.CrossJoinNode;
 import org.apache.doris.planner.DataPartition;
 import org.apache.doris.planner.ExchangeNode;
 import org.apache.doris.planner.HashJoinNode;
@@ -338,8 +341,7 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
         PlanNode rightFragmentPlanRoot = rightFragment.getPlanRoot();
         JoinType joinType = hashJoin.getJoinType();
 
-        if (joinType.equals(JoinType.CROSS_JOIN)
-                || (joinType.equals(JoinType.INNER_JOIN) && 
!hashJoin.getCondition().isPresent())) {
+        if (JoinUtils.shouldNestedLoopJoin(hashJoin)) {
             throw new RuntimeException("Physical hash join could not execute 
without equal join condition.");
         } else {
             Expression eqJoinExpression = hashJoin.getCondition().get();
@@ -368,6 +370,30 @@ public class PhysicalPlanTranslator extends 
DefaultPlanVisitor<PlanFragment, Pla
         }
     }
 
+    @Override
+    public PlanFragment 
visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
+            PlanTranslatorContext context) {
+        // NOTICE: We must visit from right to left, to ensure the last 
fragment is root fragment
+        // TODO: we should add a helper method to wrap this logic.
+        //   Maybe something like private List<PlanFragment> 
postOrderVisitChildren(
+        //       PhysicalPlan plan, PlanVisitor visitor, Context context).
+        PlanFragment rightFragment = nestedLoopJoin.child(1).accept(this, 
context);
+        PlanFragment leftFragment = nestedLoopJoin.child(0).accept(this, 
context);
+        PlanNode leftFragmentPlanRoot = leftFragment.getPlanRoot();
+        PlanNode rightFragmentPlanRoot = rightFragment.getPlanRoot();
+        if (JoinUtils.shouldNestedLoopJoin(nestedLoopJoin)) {
+            CrossJoinNode crossJoinNode =
+                    new CrossJoinNode(context.nextPlanNodeId(), 
leftFragmentPlanRoot, rightFragmentPlanRoot, null);
+            rightFragment.getPlanRoot().setCompactData(false);
+            crossJoinNode.setChild(0, leftFragment.getPlanRoot());
+            connectChildFragment(crossJoinNode, 1, leftFragment, 
rightFragment, context);
+            leftFragment.setPlanRoot(crossJoinNode);
+            return leftFragment;
+        } else {
+            throw new RuntimeException("Physical nested loop join could not 
execute with equal join condition.");
+        }
+    }
+
     // TODO: generate expression mapping when be project could do in ExecNode
     @Override
     public PlanFragment visitPhysicalProject(PhysicalProject<Plan> project, 
PlanTranslatorContext context) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/PatternDescriptor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/PatternDescriptor.java
index d2b44427c9..dd742c34e0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/PatternDescriptor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/PatternDescriptor.java
@@ -48,6 +48,10 @@ public class PatternDescriptor<INPUT_TYPE extends Plan> {
         return new PatternDescriptor<>(pattern.withPredicates(predicates), 
defaultPromise);
     }
 
+    public PatternDescriptor<INPUT_TYPE> whenNot(Predicate<INPUT_TYPE> 
predicate) {
+        return when(predicate.negate());
+    }
+
     public <OUTPUT_TYPE extends Plan> PatternMatcher<INPUT_TYPE, OUTPUT_TYPE> 
then(
             Function<INPUT_TYPE, OUTPUT_TYPE> matchedAction) {
         return new PatternMatcher<>(pattern, defaultPromise, ctx -> 
matchedAction.apply(ctx.root));
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java
index 5f6b96d82d..3a55cf858b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriver.java
@@ -21,6 +21,7 @@ import org.apache.doris.nereids.PlanContext;
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
@@ -99,6 +100,40 @@ public class ChildOutputPropertyDeriver extends 
PlanVisitor<PhysicalProperties,
         return leftOutputProperty;
     }
 
+    @Override
+    public PhysicalProperties 
visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
+            PlanContext context) {
+        // TODO: copy from hash join, should update according to nested loop 
join properties.
+        Preconditions.checkState(childrenOutputProperties.size() == 2);
+        PhysicalProperties leftOutputProperty = 
childrenOutputProperties.get(0);
+        PhysicalProperties rightOutputProperty = 
childrenOutputProperties.get(1);
+
+        // broadcast
+        if (rightOutputProperty.getDistributionSpec() instanceof 
DistributionSpecReplicated) {
+            // TODO
+            return leftOutputProperty;
+        }
+
+        // shuffle
+        // List<SlotReference> leftSlotRefs = 
hashJoin.left().getOutput().stream().map(slot -> (SlotReference) slot)
+        //        .collect(Collectors.toList());
+        // List<SlotReference> rightSlotRefs = 
hashJoin.right().getOutput().stream().map(slot -> (SlotReference) slot)
+        //                .collect(Collectors.toList());
+
+        //        List<SlotReference> leftOnSlotRefs;
+        //        List<SlotReference> rightOnSlotRefs;
+        //        Preconditions.checkState(leftOnSlotRefs.size() == 
rightOnSlotRefs.size());
+        DistributionSpec leftDistribution = 
leftOutputProperty.getDistributionSpec();
+        DistributionSpec rightDistribution = 
rightOutputProperty.getDistributionSpec();
+        if (!(leftDistribution instanceof DistributionSpecHash)
+                || !(rightDistribution instanceof DistributionSpecHash)) {
+            Preconditions.checkState(false, "error");
+            return new PhysicalProperties();
+        }
+
+        return leftOutputProperty;
+    }
+
     @Override
     public PhysicalProperties visitPhysicalOlapScan(PhysicalOlapScan olapScan, 
PlanContext context) {
         return olapScan.getPhysicalProperties();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java
index 848ed44f9d..112d0db3e6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/RequestPropertyDeriver.java
@@ -25,6 +25,7 @@ import 
org.apache.doris.nereids.properties.DistributionSpecHash.ShuffleType;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 import org.apache.doris.nereids.util.JoinUtils;
 import org.apache.doris.nereids.util.Utils;
@@ -92,6 +93,31 @@ public class RequestPropertyDeriver extends 
PlanVisitor<Void, PlanContext> {
         return null;
     }
 
+    @Override
+    public Void visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> 
nestedLoopJoin, PlanContext context) {
+        // TODO: copy from physicalHashJoin, should update according to 
physical nested loop join properties.
+        // for broadcast join
+        List<PhysicalProperties> propertiesForBroadcast = Lists.newArrayList(
+                new PhysicalProperties(),
+                new PhysicalProperties(new DistributionSpecReplicated())
+        );
+        // for shuffle join
+        Pair<List<SlotReference>, List<SlotReference>> onClauseUsedSlots
+                = JoinUtils.getOnClauseUsedSlots(nestedLoopJoin);
+        List<PhysicalProperties> propertiesForShuffle = Lists.newArrayList(
+                new PhysicalProperties(new 
DistributionSpecHash(onClauseUsedSlots.first, ShuffleType.JOIN)),
+                new PhysicalProperties(new 
DistributionSpecHash(onClauseUsedSlots.second, ShuffleType.JOIN)));
+
+        if (!JoinUtils.onlyBroadcast(nestedLoopJoin)) {
+            requestPropertyToChildren.add(propertiesForShuffle);
+        }
+        if (!JoinUtils.onlyShuffle(nestedLoopJoin)) {
+            requestPropertyToChildren.add(propertiesForBroadcast);
+        }
+
+        return null;
+    }
+
     protected static List<PhysicalProperties> 
computeShuffleJoinRequiredProperties(
             PhysicalProperties requestedProperty, List<SlotReference> 
leftShuffleColumns,
             List<SlotReference> rightShuffleColumns) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
index aafc618574..9cc7bf7449 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
@@ -21,6 +21,7 @@ import 
org.apache.doris.nereids.rules.exploration.join.JoinCommute;
 import 
org.apache.doris.nereids.rules.implementation.LogicalAggToPhysicalHashAgg;
 import 
org.apache.doris.nereids.rules.implementation.LogicalFilterToPhysicalFilter;
 import org.apache.doris.nereids.rules.implementation.LogicalJoinToHashJoin;
+import 
org.apache.doris.nereids.rules.implementation.LogicalJoinToNestedLoopJoin;
 import 
org.apache.doris.nereids.rules.implementation.LogicalLimitToPhysicalLimit;
 import 
org.apache.doris.nereids.rules.implementation.LogicalOlapScanToPhysicalOlapScan;
 import 
org.apache.doris.nereids.rules.implementation.LogicalProjectToPhysicalProject;
@@ -48,6 +49,7 @@ public class RuleSet {
             .add(new LogicalAggToPhysicalHashAgg())
             .add(new LogicalFilterToPhysicalFilter())
             .add(new LogicalJoinToHashJoin())
+            .add(new LogicalJoinToNestedLoopJoin())
             .add(new LogicalOlapScanToPhysicalOlapScan())
             .add(new LogicalProjectToPhysicalProject())
             .add(new LogicalLimitToPhysicalLimit())
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
index d1d02e54a2..18b077fd2b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -68,6 +68,7 @@ public enum RuleType {
     // implementation rules
     LOGICAL_AGG_TO_PHYSICAL_HASH_AGG_RULE(RuleTypeClass.IMPLEMENTATION),
     LOGICAL_JOIN_TO_HASH_JOIN_RULE(RuleTypeClass.IMPLEMENTATION),
+    LOGICAL_JOIN_TO_NESTED_LOOP_JOIN_RULE(RuleTypeClass.IMPLEMENTATION),
     LOGICAL_PROJECT_TO_PHYSICAL_PROJECT_RULE(RuleTypeClass.IMPLEMENTATION),
     LOGICAL_FILTER_TO_PHYSICAL_FILTER_RULE(RuleTypeClass.IMPLEMENTATION),
     LOGICAL_SORT_TO_PHYSICAL_HEAP_SORT_RULE(RuleTypeClass.IMPLEMENTATION),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java
index ee48303f1d..8e5fb996da 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.rules.implementation;
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleType;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
+import org.apache.doris.nereids.util.JoinUtils;
 
 /**
  * Implementation rule that convert logical join to physical hash join.
@@ -27,7 +28,9 @@ import 
org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
 public class LogicalJoinToHashJoin extends OneImplementationRuleFactory {
     @Override
     public Rule build() {
-        return logicalJoin().then(join -> new PhysicalHashJoin<>(
+        return logicalJoin()
+                .whenNot(JoinUtils::shouldNestedLoopJoin)
+                .then(join -> new PhysicalHashJoin<>(
             join.getJoinType(),
             join.getCondition(),
             join.getLogicalProperties(),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToNestedLoopJoin.java
similarity index 58%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToNestedLoopJoin.java
index ee48303f1d..00f1ba25ac 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToNestedLoopJoin.java
@@ -19,20 +19,23 @@ package org.apache.doris.nereids.rules.implementation;
 
 import org.apache.doris.nereids.rules.Rule;
 import org.apache.doris.nereids.rules.RuleType;
-import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
+import org.apache.doris.nereids.util.JoinUtils;
 
 /**
- * Implementation rule that convert logical join to physical hash join.
+ * Implementation rule that convert logical join to physical nested loop join.
  */
-public class LogicalJoinToHashJoin extends OneImplementationRuleFactory {
+public class LogicalJoinToNestedLoopJoin extends OneImplementationRuleFactory {
     @Override
     public Rule build() {
-        return logicalJoin().then(join -> new PhysicalHashJoin<>(
-            join.getJoinType(),
-            join.getCondition(),
-            join.getLogicalProperties(),
-            join.left(),
-            join.right())
-        ).toRule(RuleType.LOGICAL_JOIN_TO_HASH_JOIN_RULE);
+        return logicalJoin()
+                .when(JoinUtils::shouldNestedLoopJoin)
+                .then(join -> new PhysicalNestedLoopJoin<>(
+                        join.getJoinType(),
+                        join.getCondition(),
+                        join.getLogicalProperties(),
+                        join.left(),
+                        join.right())
+                ).toRule(RuleType.LOGICAL_JOIN_TO_NESTED_LOOP_JOIN_RULE);
     }
 }
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 881e3acf91..ca141471c8 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
@@ -22,14 +22,17 @@ 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.plans.JoinType;
+import org.apache.doris.nereids.trees.plans.algebra.Join;
 import org.apache.doris.nereids.util.ExpressionUtils;
 import org.apache.doris.statistics.ColumnStats;
 import org.apache.doris.statistics.StatsDeriveResult;
 
 import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 /**
  * Estimate hash join stats.
@@ -40,11 +43,13 @@ public class JoinEstimation {
     /**
      * Do estimate.
      */
-    public static StatsDeriveResult estimate(StatsDeriveResult leftStats, 
StatsDeriveResult rightStats,
-            Expression eqCondition, JoinType joinType) {
+    public static StatsDeriveResult estimate(StatsDeriveResult leftStats, 
StatsDeriveResult rightStats, Join join) {
+        Optional<Expression> eqCondition = join.getCondition();
+        JoinType joinType = join.getJoinType();
         StatsDeriveResult statsDeriveResult = new StatsDeriveResult(leftStats);
         statsDeriveResult.merge(rightStats);
-        List<Expression> eqConjunctList = 
ExpressionUtils.extractConjunction(eqCondition);
+        List<Expression> eqConjunctList = Lists.newArrayList();
+        eqCondition.ifPresent(e -> 
eqConjunctList.addAll(ExpressionUtils.extractConjunction(e)));
         long rowCount = -1;
         if (joinType.isSemiOrAntiJoin()) {
             rowCount = getSemiJoinRowCount(leftStats, rightStats, 
eqConjunctList, joinType);
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 373e105dff..e223b65f57 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
@@ -23,12 +23,12 @@ 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.Aggregate;
-import org.apache.doris.nereids.trees.plans.Filter;
-import org.apache.doris.nereids.trees.plans.Limit;
 import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.Project;
-import org.apache.doris.nereids.trees.plans.Scan;
+import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
+import org.apache.doris.nereids.trees.plans.algebra.Filter;
+import org.apache.doris.nereids.trees.plans.algebra.Limit;
+import org.apache.doris.nereids.trees.plans.algebra.Project;
+import org.apache.doris.nereids.trees.plans.algebra.Scan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
 import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
@@ -42,6 +42,7 @@ import 
org.apache.doris.nereids.trees.plans.physical.PhysicalFilter;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
 import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
@@ -119,8 +120,7 @@ public class StatsCalculator extends 
DefaultPlanVisitor<StatsDeriveResult, Void>
     @Override
     public StatsDeriveResult visitLogicalJoin(LogicalJoin<Plan, Plan> join, 
Void context) {
         return JoinEstimation.estimate(groupExpression.getCopyOfChildStats(0),
-                groupExpression.getCopyOfChildStats(1),
-                join.getCondition().get(), join.getJoinType());
+                groupExpression.getCopyOfChildStats(1), join);
     }
 
     @Override
@@ -141,8 +141,14 @@ public class StatsCalculator extends 
DefaultPlanVisitor<StatsDeriveResult, Void>
     @Override
     public StatsDeriveResult visitPhysicalHashJoin(PhysicalHashJoin<Plan, 
Plan> hashJoin, Void context) {
         return JoinEstimation.estimate(groupExpression.getCopyOfChildStats(0),
-                groupExpression.getCopyOfChildStats(1),
-                hashJoin.getCondition().get(), hashJoin.getJoinType());
+                groupExpression.getCopyOfChildStats(1), hashJoin);
+    }
+
+    @Override
+    public StatsDeriveResult 
visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
+            Void context) {
+        return JoinEstimation.estimate(groupExpression.getCopyOfChildStats(0),
+                groupExpression.getCopyOfChildStats(1), nestedLoopJoin);
     }
 
     // TODO: We should subtract those pruned column, and consider the 
expression transformations in the node.
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 29b509c884..d4fcd05531 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
@@ -17,7 +17,8 @@
 
 package org.apache.doris.nereids.trees;
 
-import com.alibaba.google.common.collect.ImmutableList;
+
+import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 import java.util.function.Consumer;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
index 6ca7462d93..53f45a7ab1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
@@ -47,6 +47,7 @@ public enum PlanType {
     PHYSICAL_SORT,
     PHYSICAL_LIMIT,
     PHYSICAL_HASH_JOIN,
+    PHYSICAL_NESTED_LOOP_JOIN,
     PHYSICAL_EXCHANGE,
     PHYSICAL_DISTRIBUTION;
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Aggregate.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Aggregate.java
similarity index 95%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Aggregate.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Aggregate.java
index 4773403ad5..774052e0fa 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Aggregate.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Aggregate.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans;
+package org.apache.doris.nereids.trees.plans.algebra;
 
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Filter.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Filter.java
similarity index 94%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Filter.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Filter.java
index 1dd37fdd06..f4371eb4f7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Filter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Filter.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans;
+package org.apache.doris.nereids.trees.plans.algebra;
 
 import org.apache.doris.nereids.trees.expressions.Expression;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Filter.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Join.java
similarity index 75%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Filter.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Join.java
index 1dd37fdd06..c2f05879e2 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Filter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Join.java
@@ -15,13 +15,18 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans;
+package org.apache.doris.nereids.trees.plans.algebra;
 
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.plans.JoinType;
+
+import java.util.Optional;
 
 /**
- * Common interface for logical/physical filter.
+ * Common interface for logical/physical join.
  */
-public interface Filter {
-    Expression getPredicates();
+public interface Join {
+    JoinType getJoinType();
+
+    Optional<Expression> getCondition();
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Limit.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Limit.java
similarity index 94%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Limit.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Limit.java
index 394eaafae3..a198d1253d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Limit.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Limit.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans;
+package org.apache.doris.nereids.trees.plans.algebra;
 
 /**
  * Common interface for logical/physical limit.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Project.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Project.java
similarity index 94%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Project.java
rename to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Project.java
index 78c3864a00..1203998a5b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Project.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Project.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans;
+package org.apache.doris.nereids.trees.plans.algebra;
 
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Scan.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java
similarity index 95%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Scan.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java
index b5bcbca786..f0c536cf83 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Scan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java
@@ -15,7 +15,7 @@
 // specific language governing permissions and limitations
 // under the License.
 
-package org.apache.doris.nereids.trees.plans;
+package org.apache.doris.nereids.trees.plans.algebra;
 
 import org.apache.doris.catalog.Table;
 import org.apache.doris.nereids.trees.expressions.Expression;
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 d60850d044..06ec298851 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
@@ -23,9 +23,9 @@ 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.AggPhase;
-import org.apache.doris.nereids.trees.plans.Aggregate;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
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 af58cc2f7c..56ecea983e 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
@@ -21,9 +21,9 @@ import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.Slot;
-import org.apache.doris.nereids.trees.plans.Filter;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.algebra.Filter;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
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 5d6f06458e..81fbafdde6 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
@@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.algebra.Join;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
@@ -39,7 +40,7 @@ import java.util.stream.Collectors;
  * Logical join plan.
  */
 public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE 
extends Plan>
-        extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
+        extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements 
Join {
 
     private final JoinType joinType;
     private final Optional<Expression> condition;
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 756a7d36e2..6b78ff2ab5 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
@@ -22,9 +22,9 @@ import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.IntegerLiteral;
 import org.apache.doris.nereids.trees.expressions.Slot;
-import org.apache.doris.nereids.trees.plans.Limit;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.algebra.Limit;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
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 6e2df85cb3..1b3f57949c 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
@@ -24,7 +24,7 @@ import 
org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
-import org.apache.doris.nereids.trees.plans.Project;
+import org.apache.doris.nereids.trees.plans.algebra.Project;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
index daa28f6841..21a977d394 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
@@ -24,7 +24,7 @@ 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.plans.PlanType;
-import org.apache.doris.nereids.trees.plans.Scan;
+import org.apache.doris.nereids.trees.plans.algebra.Scan;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 import org.apache.doris.nereids.util.Utils;
 
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 2dfc493bd3..05a97c19ff 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
@@ -22,9 +22,9 @@ import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.plans.AggPhase;
-import org.apache.doris.nereids.trees.plans.Aggregate;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
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 d7a60a8426..c2eb461bd5 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
@@ -20,9 +20,9 @@ package org.apache.doris.nereids.trees.plans.physical;
 import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.plans.Filter;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.algebra.Filter;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
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 a2f53f2e3e..6c30a0c606 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
@@ -26,10 +26,8 @@ import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 
 import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -38,12 +36,7 @@ import java.util.Optional;
 public class PhysicalHashJoin<
         LEFT_CHILD_TYPE extends Plan,
         RIGHT_CHILD_TYPE extends Plan>
-        extends PhysicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
-
-    private final JoinType joinType;
-
-    private final Optional<Expression> condition;
-
+        extends PhysicalJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
 
     public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition, 
LogicalProperties logicalProperties,
                             LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE 
rightChild) {
@@ -59,17 +52,8 @@ public class PhysicalHashJoin<
     public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition,
                             Optional<GroupExpression> groupExpression, 
LogicalProperties logicalProperties,
                             LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE 
rightChild) {
-        super(PlanType.PHYSICAL_HASH_JOIN, groupExpression, logicalProperties, 
leftChild, rightChild);
-        this.joinType = Objects.requireNonNull(joinType, "joinType can not be 
null");
-        this.condition = Objects.requireNonNull(condition, "condition can not 
be null");
-    }
-
-    public JoinType getJoinType() {
-        return joinType;
-    }
-
-    public Optional<Expression> getCondition() {
-        return condition;
+        super(PlanType.PHYSICAL_HASH_JOIN, joinType, condition,
+                groupExpression, logicalProperties, leftChild, rightChild);
     }
 
     @Override
@@ -77,11 +61,6 @@ public class PhysicalHashJoin<
         return visitor.visitPhysicalHashJoin((PhysicalHashJoin<Plan, Plan>) 
this, context);
     }
 
-    @Override
-    public List<Expression> getExpressions() {
-        return 
condition.<List<Expression>>map(ImmutableList::of).orElseGet(ImmutableList::of);
-    }
-
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -93,23 +72,6 @@ public class PhysicalHashJoin<
         return sb.toString();
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        PhysicalHashJoin that = (PhysicalHashJoin) o;
-        return joinType == that.joinType && Objects.equals(condition, 
that.condition);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(joinType, condition);
-    }
-
     @Override
     public PhysicalBinary<Plan, Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 2);
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/PhysicalJoin.java
similarity index 52%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalJoin.java
index a2f53f2e3e..d47be13f6c 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/PhysicalJoin.java
@@ -23,9 +23,8 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
-import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.nereids.trees.plans.algebra.Join;
 
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
@@ -33,33 +32,26 @@ import java.util.Objects;
 import java.util.Optional;
 
 /**
- * Physical hash join plan.
+ * Abstract class for all physical join node.
  */
-public class PhysicalHashJoin<
+public abstract class PhysicalJoin<
         LEFT_CHILD_TYPE extends Plan,
         RIGHT_CHILD_TYPE extends Plan>
-        extends PhysicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
+        extends PhysicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements 
Join {
+    protected final JoinType joinType;
 
-    private final JoinType joinType;
-
-    private final Optional<Expression> condition;
-
-
-    public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition, 
LogicalProperties logicalProperties,
-                            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE 
rightChild) {
-        this(joinType, condition, Optional.empty(), logicalProperties, 
leftChild, rightChild);
-    }
+    protected final Optional<Expression> condition;
 
     /**
-     * Constructor of PhysicalHashJoinNode.
+     * Constructor of PhysicalJoin.
      *
      * @param joinType Which join type, left semi join, inner join...
      * @param condition join condition.
      */
-    public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition,
-                            Optional<GroupExpression> groupExpression, 
LogicalProperties logicalProperties,
-                            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE 
rightChild) {
-        super(PlanType.PHYSICAL_HASH_JOIN, groupExpression, logicalProperties, 
leftChild, rightChild);
+    public PhysicalJoin(PlanType type, JoinType joinType, Optional<Expression> 
condition,
+            Optional<GroupExpression> groupExpression, LogicalProperties 
logicalProperties,
+            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
+        super(type, groupExpression, logicalProperties, leftChild, rightChild);
         this.joinType = Objects.requireNonNull(joinType, "joinType can not be 
null");
         this.condition = Objects.requireNonNull(condition, "condition can not 
be null");
     }
@@ -72,27 +64,11 @@ public class PhysicalHashJoin<
         return condition;
     }
 
-    @Override
-    public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
-        return visitor.visitPhysicalHashJoin((PhysicalHashJoin<Plan, Plan>) 
this, context);
-    }
-
     @Override
     public List<Expression> getExpressions() {
         return 
condition.<List<Expression>>map(ImmutableList::of).orElseGet(ImmutableList::of);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("PhysicalHashJoin ([").append(joinType).append("]");
-        condition.ifPresent(
-                expression -> sb.append(", [").append(expression).append("]")
-        );
-        sb.append(")");
-        return sb.toString();
-    }
-
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -101,7 +77,7 @@ public class PhysicalHashJoin<
         if (o == null || getClass() != o.getClass()) {
             return false;
         }
-        PhysicalHashJoin that = (PhysicalHashJoin) o;
+        PhysicalJoin that = (PhysicalJoin) o;
         return joinType == that.joinType && Objects.equals(condition, 
that.condition);
     }
 
@@ -109,21 +85,4 @@ public class PhysicalHashJoin<
     public int hashCode() {
         return Objects.hash(joinType, condition);
     }
-
-    @Override
-    public PhysicalBinary<Plan, Plan> withChildren(List<Plan> children) {
-        Preconditions.checkArgument(children.size() == 2);
-        return new PhysicalHashJoin<>(joinType, condition, logicalProperties, 
children.get(0), children.get(1));
-    }
-
-    @Override
-    public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new PhysicalHashJoin<>(joinType, condition, groupExpression, 
logicalProperties, left(), right());
-    }
-
-    @Override
-    public Plan withLogicalProperties(Optional<LogicalProperties> 
logicalProperties) {
-        return new PhysicalHashJoin<>(joinType, condition, Optional.empty(),
-            logicalProperties.get(), 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 b7e07167e0..6124bd7da9 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
@@ -21,9 +21,9 @@ import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.IntegerLiteral;
-import org.apache.doris.nereids.trees.plans.Limit;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.algebra.Limit;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
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/PhysicalNestedLoopJoin.java
similarity index 50%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalNestedLoopJoin.java
index a2f53f2e3e..0e3452adc9 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/PhysicalNestedLoopJoin.java
@@ -26,66 +26,46 @@ import org.apache.doris.nereids.trees.plans.PlanType;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 
 import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
 
 /**
- * Physical hash join plan.
+ * Use nested loop algorithm to do join.
  */
-public class PhysicalHashJoin<
+public class PhysicalNestedLoopJoin<
         LEFT_CHILD_TYPE extends Plan,
         RIGHT_CHILD_TYPE extends Plan>
-        extends PhysicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
+        extends PhysicalJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
 
-    private final JoinType joinType;
-
-    private final Optional<Expression> condition;
-
-
-    public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition, 
LogicalProperties logicalProperties,
-                            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE 
rightChild) {
+    public PhysicalNestedLoopJoin(JoinType joinType, Optional<Expression> 
condition,
+            LogicalProperties logicalProperties, LEFT_CHILD_TYPE leftChild, 
RIGHT_CHILD_TYPE rightChild) {
         this(joinType, condition, Optional.empty(), logicalProperties, 
leftChild, rightChild);
     }
 
     /**
-     * Constructor of PhysicalHashJoinNode.
+     * Constructor of PhysicalNestedLoopJoin.
      *
      * @param joinType Which join type, left semi join, inner join...
      * @param condition join condition.
      */
-    public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition,
-                            Optional<GroupExpression> groupExpression, 
LogicalProperties logicalProperties,
-                            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE 
rightChild) {
-        super(PlanType.PHYSICAL_HASH_JOIN, groupExpression, logicalProperties, 
leftChild, rightChild);
-        this.joinType = Objects.requireNonNull(joinType, "joinType can not be 
null");
-        this.condition = Objects.requireNonNull(condition, "condition can not 
be null");
-    }
-
-    public JoinType getJoinType() {
-        return joinType;
-    }
-
-    public Optional<Expression> getCondition() {
-        return condition;
+    public PhysicalNestedLoopJoin(JoinType joinType, Optional<Expression> 
condition,
+            Optional<GroupExpression> groupExpression, LogicalProperties 
logicalProperties,
+            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
+        super(PlanType.PHYSICAL_NESTED_LOOP_JOIN, joinType, condition,
+                groupExpression, logicalProperties, leftChild, rightChild);
     }
 
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
-        return visitor.visitPhysicalHashJoin((PhysicalHashJoin<Plan, Plan>) 
this, context);
-    }
-
-    @Override
-    public List<Expression> getExpressions() {
-        return 
condition.<List<Expression>>map(ImmutableList::of).orElseGet(ImmutableList::of);
+        return 
visitor.visitPhysicalNestedLoopJoin((PhysicalNestedLoopJoin<Plan, Plan>) this, 
context);
     }
 
     @Override
     public String toString() {
+        // TODO: Maybe we could pull up this to the abstract class in the 
future.
         StringBuilder sb = new StringBuilder();
-        sb.append("PhysicalHashJoin ([").append(joinType).append("]");
+        sb.append("PhysicalNestedLoopJoin ([").append(joinType).append("]");
         condition.ifPresent(
                 expression -> sb.append(", [").append(expression).append("]")
         );
@@ -93,37 +73,20 @@ public class PhysicalHashJoin<
         return sb.toString();
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        PhysicalHashJoin that = (PhysicalHashJoin) o;
-        return joinType == that.joinType && Objects.equals(condition, 
that.condition);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(joinType, condition);
-    }
-
     @Override
     public PhysicalBinary<Plan, Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 2);
-        return new PhysicalHashJoin<>(joinType, condition, logicalProperties, 
children.get(0), children.get(1));
+        return new PhysicalNestedLoopJoin<>(joinType, condition, 
logicalProperties, children.get(0), children.get(1));
     }
 
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) 
{
-        return new PhysicalHashJoin<>(joinType, condition, groupExpression, 
logicalProperties, left(), right());
+        return new PhysicalNestedLoopJoin<>(joinType, condition, 
groupExpression, logicalProperties, left(), right());
     }
 
     @Override
     public Plan withLogicalProperties(Optional<LogicalProperties> 
logicalProperties) {
-        return new PhysicalHashJoin<>(joinType, condition, Optional.empty(),
-            logicalProperties.get(), left(), right());
+        return new PhysicalNestedLoopJoin<>(joinType, condition, 
Optional.empty(),
+                logicalProperties.get(), left(), right());
     }
 }
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 7f4c2151f6..fd9b66bba3 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
@@ -23,7 +23,7 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.plans.Plan;
 import org.apache.doris.nereids.trees.plans.PlanType;
-import org.apache.doris.nereids.trees.plans.Project;
+import org.apache.doris.nereids.trees.plans.algebra.Project;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.base.Preconditions;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java
index 485e5d926c..93898031c2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java
@@ -21,7 +21,7 @@ import org.apache.doris.nereids.memo.GroupExpression;
 import org.apache.doris.nereids.properties.LogicalProperties;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.plans.PlanType;
-import org.apache.doris.nereids.trees.plans.Scan;
+import org.apache.doris.nereids.trees.plans.algebra.Scan;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 
 import com.google.common.collect.ImmutableList;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java
index 5c11a43424..2f91e1f7f3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java
@@ -37,6 +37,7 @@ import 
org.apache.doris.nereids.trees.plans.physical.PhysicalFilter;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalRelation;
@@ -136,6 +137,10 @@ public abstract class PlanVisitor<R, C> {
         return visit(hashJoin, context);
     }
 
+    public R visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> 
nestedLoopJoin, C context) {
+        return visit(nestedLoopJoin, context);
+    }
+
     public R visitPhysicalProject(PhysicalProject<Plan> project, C context) {
         return visit(project, context);
     }
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 5c66dc85a2..23417ae1d3 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
@@ -21,8 +21,10 @@ import org.apache.doris.common.Pair;
 import org.apache.doris.nereids.trees.expressions.EqualTo;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.Plan;
-import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
+import org.apache.doris.nereids.trees.plans.algebra.Join;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalJoin;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
@@ -34,19 +36,19 @@ import java.util.List;
  * Utils for join
  */
 public class JoinUtils {
-    public static boolean onlyBroadcast(PhysicalHashJoin join) {
+    public static boolean onlyBroadcast(PhysicalJoin join) {
         // Cross-join only can be broadcast join.
         return join.getJoinType().isCrossJoin();
     }
 
-    public static boolean onlyShuffle(PhysicalHashJoin join) {
+    public static boolean onlyShuffle(PhysicalJoin join) {
         return join.getJoinType().isRightJoin() || 
join.getJoinType().isFullOuterJoin();
     }
 
     /**
      * Get all equalTo from onClause of join
      */
-    public static List<EqualTo> getEqualTo(PhysicalHashJoin<Plan, Plan> join) {
+    public static List<EqualTo> getEqualTo(PhysicalJoin<Plan, Plan> join) {
         List<EqualTo> eqConjuncts = Lists.newArrayList();
         if (!join.getCondition().isPresent()) {
             return eqConjuncts;
@@ -86,7 +88,7 @@ public class JoinUtils {
      * Return pair of left used slots and right used slots.
      */
     public static Pair<List<SlotReference>, List<SlotReference>> 
getOnClauseUsedSlots(
-            PhysicalHashJoin<Plan, Plan> join) {
+            PhysicalJoin<Plan, Plan> join) {
         Pair<List<SlotReference>, List<SlotReference>> childSlots =
                 new Pair<>(Lists.newArrayList(), Lists.newArrayList());
 
@@ -114,4 +116,9 @@ public class JoinUtils {
 
         return childSlots;
     }
+
+    public static boolean shouldNestedLoopJoin(Join join) {
+        JoinType joinType = join.getJoinType();
+        return (joinType.isInnerJoin() && !join.getCondition().isPresent()) || 
joinType.isCrossJoin();
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
index ff3195d7fb..a22d0f27d2 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/stats/StatsCalculatorTest.java
@@ -32,6 +32,7 @@ import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.functions.AggregateFunction;
 import org.apache.doris.nereids.trees.expressions.functions.Sum;
+import org.apache.doris.nereids.trees.plans.FakeJoin;
 import org.apache.doris.nereids.trees.plans.GroupPlan;
 import org.apache.doris.nereids.trees.plans.JoinType;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
@@ -190,11 +191,13 @@ public class StatsCalculatorTest {
         StatsDeriveResult rightStats = new StatsDeriveResult(rightRowCount, 
slotColumnStatsMap2);
 
         EqualTo equalTo = new EqualTo(slot1, slot2);
-        StatsDeriveResult semiJoinStats = JoinEstimation.estimate(leftStats,
-                rightStats, equalTo, JoinType.LEFT_SEMI_JOIN);
+
+        FakeJoin fakeSemiJoin = new FakeJoin(JoinType.LEFT_SEMI_JOIN, 
Optional.of(equalTo));
+        FakeJoin fakeInnerJoin = new FakeJoin(JoinType.INNER_JOIN, 
Optional.of(equalTo));
+
+        StatsDeriveResult semiJoinStats = JoinEstimation.estimate(leftStats, 
rightStats, fakeSemiJoin);
         Assertions.assertEquals(leftRowCount, semiJoinStats.getRowCount());
-        StatsDeriveResult innerJoinStats = JoinEstimation.estimate(leftStats,
-                rightStats, equalTo, JoinType.INNER_JOIN);
+        StatsDeriveResult innerJoinStats = JoinEstimation.estimate(leftStats, 
rightStats, fakeInnerJoin);
         Assertions.assertEquals(2500000, innerJoinStats.getRowCount());
     }
 
@@ -240,7 +243,6 @@ public class StatsCalculatorTest {
         Assertions.assertNotNull(stats.getSlotToColumnStats().get(slot1));
     }
 
-
     @Test
     public void testLimit() {
         List<String> qualifier = new ArrayList<>();
@@ -276,6 +278,5 @@ public class StatsCalculatorTest {
         ColumnStats slot1Stats = limitStats.getSlotToColumnStats().get(slot1);
         Assertions.assertEquals(1, slot1Stats.getNdv());
         Assertions.assertEquals(1, slot1Stats.getNumNulls());
-
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Scan.java 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/FakeJoin.java
similarity index 63%
rename from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Scan.java
rename to 
fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/FakeJoin.java
index b5bcbca786..431abccae1 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Scan.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/FakeJoin.java
@@ -17,22 +17,27 @@
 
 package org.apache.doris.nereids.trees.plans;
 
-import org.apache.doris.catalog.Table;
 import org.apache.doris.nereids.trees.expressions.Expression;
-import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.algebra.Join;
 
-import java.util.Collections;
-import java.util.List;
+import java.util.Optional;
 
-/**
- * Common interface for logical/physical scan.
- */
-public interface Scan {
-    List<Expression> getExpressions();
+public class FakeJoin implements Join {
+    private final JoinType joinType;
+    private final Optional<Expression> condition;
 
-    Table getTable();
+    public FakeJoin(JoinType joinType, Optional<Expression> condition) {
+        this.joinType = joinType;
+        this.condition = condition;
+    }
+
+    @Override
+    public JoinType getJoinType() {
+        return joinType;
+    }
 
-    default List<Slot> getOutput() {
-        return Collections.emptyList();
+    @Override
+    public Optional<Expression> getCondition() {
+        return condition;
     }
 }
diff --git a/regression-test/data/nereids_syntax_p0/join.out 
b/regression-test/data/nereids_syntax_p0/join.out
index 2a1cc0480a..2285f8357e 100644
--- a/regression-test/data/nereids_syntax_p0/join.out
+++ b/regression-test/data/nereids_syntax_p0/join.out
@@ -43,3 +43,14 @@
 
 -- !right_anti_join --
 
+-- !cross_join --
+1309892        1       1303    1432    15      19920517        3-MEDIUM        
0       24      2959704 5119906 7       2752524 73992   0       19920619        
TRUCK   15      Supplier#000000015      DF35PepL5saAK   INDIA    0      INDIA   
ASIA    18-687-542-7601
+1309892        1       1303    1432    15      19920517        3-MEDIUM        
0       24      2959704 5119906 7       2752524 73992   0       19920619        
TRUCK   29      Supplier#000000029      VVSymB3fbwaN    ARGENTINA4      
ARGENTINA       AMERICA 11-773-203-7342
+1309892        1       1303    1432    15      19920517        3-MEDIUM        
0       24      2959704 5119906 7       2752524 73992   0       19920619        
TRUCK   9       Supplier#000000009      ,gJ6K2MKveYxQT  IRAN     6      IRAN    
MIDDLE EAST     20-338-906-3675
+1309892        2       1303    1165    9       19920517        3-MEDIUM        
0       21      2404899 5119906 8       2212507 68711   7       19920616        
RAIL    15      Supplier#000000015      DF35PepL5saAK   INDIA    0      INDIA   
ASIA    18-687-542-7601
+1309892        2       1303    1165    9       19920517        3-MEDIUM        
0       21      2404899 5119906 8       2212507 68711   7       19920616        
RAIL    29      Supplier#000000029      VVSymB3fbwaN    ARGENTINA4      
ARGENTINA       AMERICA 11-773-203-7342
+1309892        2       1303    1165    9       19920517        3-MEDIUM        
0       21      2404899 5119906 8       2212507 68711   7       19920616        
RAIL    9       Supplier#000000009      ,gJ6K2MKveYxQT  IRAN     6      IRAN    
MIDDLE EAST     20-338-906-3675
+1310179        6       1312    1455    29      19921110        3-MEDIUM        
0       15      1705830 20506457        10      1535247 68233   8       
19930114        FOB     15      Supplier#000000015      DF35PepL5saAK   INDIA   
 0      INDIA   ASIA    18-687-542-7601
+1310179        6       1312    1455    29      19921110        3-MEDIUM        
0       15      1705830 20506457        10      1535247 68233   8       
19930114        FOB     29      Supplier#000000029      VVSymB3fbwaN    
ARGENTINA4      ARGENTINA       AMERICA 11-773-203-7342
+1310179        6       1312    1455    29      19921110        3-MEDIUM        
0       15      1705830 20506457        10      1535247 68233   8       
19930114        FOB     9       Supplier#000000009      ,gJ6K2MKveYxQT  IRAN    
 6      IRAN    MIDDLE EAST     20-338-906-3675
+
diff --git a/regression-test/suites/nereids_syntax_p0/join.groovy 
b/regression-test/suites/nereids_syntax_p0/join.groovy
index 0f598e78b1..ccae67bf71 100644
--- a/regression-test/suites/nereids_syntax_p0/join.groovy
+++ b/regression-test/suites/nereids_syntax_p0/join.groovy
@@ -63,5 +63,9 @@ suite("join") {
     order_qt_right_anti_join """
         SELECT * FROM lineorder RIGHT ANTI JOIN supplier ON 
lineorder.lo_suppkey = supplier.s_suppkey
     """
+
+    order_qt_cross_join """
+        SELECT * FROM lineorder CROSS JOIN supplier;
+    """
 }
 


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

Reply via email to