You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by ku...@apache.org on 2019/05/18 12:39:41 UTC

[flink] branch master updated: [FLINK-12519] [table-planner-blink] Introduce transpose rules about semi/anti join

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4fa3871  [FLINK-12519] [table-planner-blink] Introduce transpose rules about semi/anti join
4fa3871 is described below

commit 4fa387164cea44f8e0bac1aadab11433c0f0ff2b
Author: godfrey he <go...@163.com>
AuthorDate: Sat May 18 20:39:26 2019 +0800

    [FLINK-12519] [table-planner-blink] Introduce transpose rules about semi/anti join
    
    This closes #8450
---
 .../FlinkSemiAntiJoinFilterTransposeRule.java      |   91 ++
 .../FlinkSemiAntiJoinJoinTransposeRule.java        |  281 +++++
 .../FlinkSemiAntiJoinProjectTransposeRule.java     |  202 ++++
 .../table/plan/rules/FlinkBatchRuleSets.scala      |    9 +-
 .../table/plan/rules/FlinkStreamRuleSets.scala     |    9 +-
 .../logical/ProjectSemiAntiJoinTransposeRule.scala |  167 +++
 .../sql/join/BroadcastHashSemiAntiJoinTest.xml     |  163 +--
 .../batch/sql/join/NestedLoopSemiAntiJoinTest.xml  |  280 ++---
 .../table/plan/batch/sql/join/SemiAntiJoinTest.xml |  282 ++---
 .../sql/join/ShuffledHashSemiAntiJoinTest.xml      |  202 ++--
 .../batch/sql/join/SortMergeSemiAntiJoinTest.xml   |  202 ++--
 .../FlinkSemiAntiJoinFilterTransposeRuleTest.xml   |   79 ++
 .../FlinkSemiAntiJoinJoinTransposeRuleTest.xml     | 1135 ++++++++++++++++++++
 .../FlinkSemiAntiJoinProjectTransposeRuleTest.xml  |   97 ++
 .../ProjectSemiAntiJoinTransposeRuleTest.xml       |  463 ++++++++
 .../plan/stream/sql/join/SemiAntiJoinTest.xml      |  282 ++---
 .../FlinkSemiAntiJoinFilterTransposeRuleTest.scala |   74 ++
 .../FlinkSemiAntiJoinJoinTransposeRuleTest.scala   |  357 ++++++
 ...FlinkSemiAntiJoinProjectTransposeRuleTest.scala |   79 ++
 .../ProjectSemiAntiJoinTransposeRuleTest.scala     |  149 +++
 20 files changed, 3919 insertions(+), 684 deletions(-)

diff --git a/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRule.java b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRule.java
new file mode 100644
index 0000000..73c7036
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRule.java
@@ -0,0 +1,91 @@
+/*
+ * 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.flink.table.plan.rules.logical;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.logical.LogicalFilter;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.tools.RelBuilderFactory;
+
+/**
+ * This rules is copied from Calcite's {@link org.apache.calcite.rel.rules.SemiJoinFilterTransposeRule}.
+ * Modification:
+ * - Match Join with SEMI or ANTI type instead of SemiJoin
+ */
+
+/**
+ * Planner rule that pushes
+ * {@link org.apache.calcite.rel.core.SemiJoin}s down in a tree past
+ * a {@link org.apache.calcite.rel.core.Filter}.
+ *
+ * <p>The intention is to trigger other rules that will convert
+ * {@code SemiJoin}s.
+ *
+ * <p>SemiJoin(LogicalFilter(X), Y) &rarr; LogicalFilter(SemiJoin(X, Y))
+ *
+ * @see SemiJoinProjectTransposeRule
+ */
+public class FlinkSemiAntiJoinFilterTransposeRule extends RelOptRule {
+	public static final FlinkSemiAntiJoinFilterTransposeRule INSTANCE =
+			new FlinkSemiAntiJoinFilterTransposeRule(RelFactories.LOGICAL_BUILDER);
+
+	//~ Constructors -----------------------------------------------------------
+
+	/**
+	 * Creates a FlinkSemiAntiJoinFilterTransposeRule.
+	 */
+	public FlinkSemiAntiJoinFilterTransposeRule(RelBuilderFactory relBuilderFactory) {
+		super(operand(LogicalJoin.class,
+				some(operand(LogicalFilter.class, any()))),
+				relBuilderFactory, null);
+	}
+
+	//~ Methods ----------------------------------------------------------------
+
+	@Override
+	public boolean matches(RelOptRuleCall call) {
+		LogicalJoin join = call.rel(0);
+		return join.getJoinType() == JoinRelType.SEMI || join.getJoinType() == JoinRelType.ANTI;
+	}
+
+	// implement RelOptRule
+	public void onMatch(RelOptRuleCall call) {
+		LogicalJoin join = call.rel(0);
+		LogicalFilter filter = call.rel(1);
+
+		RelNode newJoin = LogicalJoin.create(
+				filter.getInput(),
+				join.getRight(),
+				join.getCondition(),
+				join.getVariablesSet(),
+				join.getJoinType());
+
+		final RelFactories.FilterFactory factory =
+				RelFactories.DEFAULT_FILTER_FACTORY;
+		RelNode newFilter =
+				factory.createFilter(newJoin, filter.getCondition());
+
+		call.transformTo(newFilter);
+	}
+}
+
+// End FlinkSemiAntiJoinFilterTransposeRule.java
diff --git a/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRule.java b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRule.java
new file mode 100644
index 0000000..0bea511
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRule.java
@@ -0,0 +1,281 @@
+/*
+ * 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.flink.table.plan.rules.logical;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.util.ImmutableBitSet;
+import org.apache.calcite.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This rules is copied from Calcite's {@link org.apache.calcite.rel.rules.SemiJoinJoinTransposeRule}.
+ * Modification:
+ * - Match Join with SEMI or ANTI type instead of SemiJoin
+ * - Unsupported (NOT) EXISTS with uncorrelation.
+ * e.g. SELECT * FROM x, y WHERE x.c = y.f AND EXISTS (SELECT * FROM z)
+ * - Unsupported keys in SEMI/ANTI Join condition are from both Join's left and Join's right
+ * e.g. SELECT * FROM x, y WHERE x.c = y.f AND x.a IN (SELECT z.i FROM z WHERE y.e = z.j)
+ */
+
+/**
+ * Planner rule that pushes a {@link org.apache.calcite.rel.core.SemiJoin}
+ * down in a tree past a {@link org.apache.calcite.rel.core.Join}
+ * in order to trigger other rules that will convert {@code SemiJoin}s.
+ *
+ * <ul>
+ * <li>SemiJoin(LogicalJoin(X, Y), Z) &rarr; LogicalJoin(SemiJoin(X, Z), Y)
+ * <li>SemiJoin(LogicalJoin(X, Y), Z) &rarr; LogicalJoin(X, SemiJoin(Y, Z))
+ * </ul>
+ *
+ * <p>Whether this
+ * first or second conversion is applied depends on which operands actually
+ * participate in the semi-join.</p>
+ */
+public class FlinkSemiAntiJoinJoinTransposeRule extends RelOptRule {
+	public static final FlinkSemiAntiJoinJoinTransposeRule INSTANCE =
+			new FlinkSemiAntiJoinJoinTransposeRule();
+
+	//~ Constructors -----------------------------------------------------------
+
+	/**
+	 * Creates a FlinkSemiAntiJoinJoinTransposeRule.
+	 */
+	private FlinkSemiAntiJoinJoinTransposeRule() {
+		super(operand(LogicalJoin.class,
+				some(operand(LogicalJoin.class, any()))));
+	}
+
+	//~ Methods ----------------------------------------------------------------
+
+	// implement RelOptRule
+	public void onMatch(RelOptRuleCall call) {
+		LogicalJoin semiAntiJoin = call.rel(0);
+		if (semiAntiJoin.getJoinType() != JoinRelType.SEMI &&
+				semiAntiJoin.getJoinType() != JoinRelType.ANTI) {
+			return;
+		}
+
+		final Join join = call.rel(1);
+		if (join.getJoinType() == JoinRelType.SEMI ||
+				join.getJoinType() == JoinRelType.ANTI) {
+			return;
+		}
+		// TODO support other join type
+		if (join.getJoinType() != JoinRelType.INNER) {
+			return;
+		}
+
+		// unsupported cases:
+		// 1. (NOT) EXISTS with uncorrelation
+		// 2. keys in SemiJoin condition are from both Join's left and Join's right
+
+		Pair<ImmutableBitSet, ImmutableBitSet> inputRefs = getSemiAntiJoinConditionInputRefs(semiAntiJoin);
+		final ImmutableBitSet leftInputRefs = inputRefs.left;
+		final ImmutableBitSet rightInputRefs = inputRefs.right;
+		// unsupported case1. (NOT) EXISTS with uncorrelation
+		// e.g. SELECT * FROM x, y WHERE x.c = y.f AND EXISTS (SELECT * FROM z)
+		// SemiJoin may be push to both Join's left and Join's right.
+		// TODO currently we does not handle this
+		if (leftInputRefs.isEmpty() || rightInputRefs.isEmpty()) {
+			return;
+		}
+
+		// X is the left child of the join below the semi-join
+		// Y is the right child of the join below the semi-join
+		// Z is the right child of the semi-join
+		int nFieldsX = join.getLeft().getRowType().getFieldList().size();
+		int nFieldsY = join.getRight().getRowType().getFieldList().size();
+		int nFieldsZ = semiAntiJoin.getRight().getRowType().getFieldList().size();
+		int nTotalFields = nFieldsX + nFieldsY + nFieldsZ;
+		List<RelDataTypeField> fields = new ArrayList<RelDataTypeField>();
+
+		// create a list of fields for the full join result; note that
+		// we can't simply use the fields from the semi-join because the
+		// row-type of a semi-join only includes the left hand side fields
+		List<RelDataTypeField> joinFields =
+				semiAntiJoin.getRowType().getFieldList();
+		for (int i = 0; i < (nFieldsX + nFieldsY); i++) {
+			fields.add(joinFields.get(i));
+		}
+		joinFields = semiAntiJoin.getRight().getRowType().getFieldList();
+		for (int i = 0; i < nFieldsZ; i++) {
+			fields.add(joinFields.get(i));
+		}
+
+		// determine which operands below the semi-join are the actual
+		// Rels that participate in the semi-join
+		int nKeysFromX = 0;
+		int nKeysFromY = 0;
+		for (int leftKey : leftInputRefs) {
+			if (leftKey < nFieldsX) {
+				nKeysFromX++;
+			} else {
+				nKeysFromY++;
+			}
+		}
+
+		// unsupported case2. keys in SemiJoin condition are from both Join's left and Join's right
+		// e.g. SELECT * FROM x, y WHERE x.c = y.f AND x.a IN (SELECT z.i FROM z WHERE y.e = z.j)
+		if (nKeysFromX > 0 && nKeysFromY > 0) {
+			return;
+		}
+
+		// the keys must all originate from either the left or right;
+		// otherwise, a semi-join wouldn't have been created
+		assert (nKeysFromX == 0) || (nKeysFromX == leftInputRefs.cardinality());
+		assert (nKeysFromY == 0) || (nKeysFromY == leftInputRefs.cardinality());
+
+		// need to convert the semi/anti join condition and possibly the keys
+		RexNode newSemiAntiJoinFilter;
+		int[] adjustments = new int[nTotalFields];
+		if (nKeysFromX > 0) {
+			// (X, Y, Z) --> (X, Z, Y)
+			// semiJoin(X, Z)
+			// pass 0 as Y's adjustment because there shouldn't be any
+			// references to Y in the semi/anti join filter
+			setJoinAdjustments(
+					adjustments,
+					nFieldsX,
+					nFieldsY,
+					nFieldsZ,
+					0,
+					-nFieldsY);
+			newSemiAntiJoinFilter =
+					semiAntiJoin.getCondition().accept(
+							new RelOptUtil.RexInputConverter(
+									semiAntiJoin.getCluster().getRexBuilder(),
+									fields,
+									adjustments));
+		} else {
+			// (X, Y, Z) --> (X, Y, Z)
+			// semiJoin(Y, Z)
+			setJoinAdjustments(
+					adjustments,
+					nFieldsX,
+					nFieldsY,
+					nFieldsZ,
+					-nFieldsX,
+					-nFieldsX);
+			newSemiAntiJoinFilter =
+					semiAntiJoin.getCondition().accept(
+							new RelOptUtil.RexInputConverter(
+									semiAntiJoin.getCluster().getRexBuilder(),
+									fields,
+									adjustments));
+		}
+
+		// create the new join
+		RelNode newSemiAntiJoinLeft;
+		if (nKeysFromX > 0) {
+			newSemiAntiJoinLeft = join.getLeft();
+		} else {
+			newSemiAntiJoinLeft = join.getRight();
+		}
+		Join newSemiAntiJoin = LogicalJoin.create(
+				newSemiAntiJoinLeft,
+				semiAntiJoin.getRight(),
+				newSemiAntiJoinFilter,
+				semiAntiJoin.getVariablesSet(),
+				semiAntiJoin.getJoinType());
+
+		RelNode leftJoinRel;
+		RelNode rightJoinRel;
+		if (nKeysFromX > 0) {
+			leftJoinRel = newSemiAntiJoin;
+			rightJoinRel = join.getRight();
+		} else {
+			leftJoinRel = join.getLeft();
+			rightJoinRel = newSemiAntiJoin;
+		}
+
+		RelNode newJoinRel =
+				join.copy(
+						join.getTraitSet(),
+						join.getCondition(),
+						leftJoinRel,
+						rightJoinRel,
+						join.getJoinType(),
+						join.isSemiJoinDone());
+
+		call.transformTo(newJoinRel);
+	}
+
+	/**
+	 * Sets an array to reflect how much each index corresponding to a field
+	 * needs to be adjusted. The array corresponds to fields in a 3-way join
+	 * between (X, Y, and Z). X remains unchanged, but Y and Z need to be
+	 * adjusted by some fixed amount as determined by the input.
+	 *
+	 * @param adjustments array to be filled out
+	 * @param nFieldsX number of fields in X
+	 * @param nFieldsY number of fields in Y
+	 * @param nFieldsZ number of fields in Z
+	 * @param adjustY the amount to adjust Y by
+	 * @param adjustZ the amount to adjust Z by
+	 */
+	private void setJoinAdjustments(
+			int[] adjustments,
+			int nFieldsX,
+			int nFieldsY,
+			int nFieldsZ,
+			int adjustY,
+			int adjustZ) {
+		for (int i = 0; i < nFieldsX; i++) {
+			adjustments[i] = 0;
+		}
+		for (int i = nFieldsX; i < (nFieldsX + nFieldsY); i++) {
+			adjustments[i] = adjustY;
+		}
+		for (int i = nFieldsX + nFieldsY; i < (nFieldsX + nFieldsY + nFieldsZ); i++) {
+			adjustments[i] = adjustZ;
+		}
+	}
+
+	private Pair<ImmutableBitSet, ImmutableBitSet> getSemiAntiJoinConditionInputRefs(Join semiAntiJoin) {
+		final int leftInputFieldCount = semiAntiJoin.getLeft().getRowType().getFieldCount();
+		final ImmutableBitSet.Builder leftInputBitSet = ImmutableBitSet.builder();
+		final ImmutableBitSet.Builder rightInputBitSet = ImmutableBitSet.builder();
+		semiAntiJoin.getCondition().accept(new RexVisitorImpl<Void>(true) {
+			public Void visitInputRef(RexInputRef inputRef) {
+				int index = inputRef.getIndex();
+				if (index < leftInputFieldCount) {
+					leftInputBitSet.set(index);
+				} else {
+					rightInputBitSet.set(index);
+				}
+				return null;
+			}
+		});
+		return new Pair<>(leftInputBitSet.build(), rightInputBitSet.build());
+	}
+}
+
+// End FlinkSemiAntiJoinJoinTransposeRule.java
diff --git a/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRule.java b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRule.java
new file mode 100644
index 0000000..2a6611b
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/java/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRule.java
@@ -0,0 +1,202 @@
+/*
+ * 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.flink.table.plan.rules.logical;
+
+import org.apache.calcite.plan.RelOptRule;
+import org.apache.calcite.plan.RelOptRuleCall;
+import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.JoinRelType;
+import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.logical.LogicalJoin;
+import org.apache.calcite.rel.logical.LogicalProject;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.rex.RexBuilder;
+import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.rex.RexProgramBuilder;
+import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.tools.RelBuilderFactory;
+import org.apache.calcite.util.Pair;
+
+import java.util.List;
+
+/**
+ * This rules is copied from Calcite's {@link org.apache.calcite.rel.rules.SemiJoinProjectTransposeRule}.
+ * Modification:
+ * - Match Join with SEMI or ANTI type instead of SemiJoin
+ * - Add predicate to check all expressions in Project should be RexInputRef
+ */
+
+/**
+ * Planner rule that pushes
+ * a {@link org.apache.calcite.rel.core.SemiJoin} down in a tree past
+ * a {@link org.apache.calcite.rel.core.Project}.
+ *
+ * <p>The intention is to trigger other rules that will convert
+ * {@code SemiJoin}s.
+ *
+ * <p>SemiJoin(LogicalProject(X), Y) &rarr; LogicalProject(SemiJoin(X, Y))
+ *
+ * @see org.apache.calcite.rel.rules.SemiJoinFilterTransposeRule
+ */
+public class FlinkSemiAntiJoinProjectTransposeRule extends RelOptRule {
+
+	public static final FlinkSemiAntiJoinProjectTransposeRule INSTANCE =
+			new FlinkSemiAntiJoinProjectTransposeRule(RelFactories.LOGICAL_BUILDER);
+
+	//~ Constructors -----------------------------------------------------------
+
+	/**
+	 * Creates a FlinkSemiAntiJoinProjectTransposeRule.
+	 */
+	private FlinkSemiAntiJoinProjectTransposeRule(RelBuilderFactory relBuilderFactory) {
+		super(operand(LogicalJoin.class,
+				some(operand(LogicalProject.class, any()))),
+				relBuilderFactory, null);
+	}
+
+	@Override
+	public boolean matches(RelOptRuleCall call) {
+		LogicalJoin join = call.rel(0);
+		LogicalProject project = call.rel(1);
+
+		// only accept SEMI/ANTI join
+		JoinRelType joinType = join.getJoinType();
+		if (joinType != JoinRelType.SEMI && joinType != JoinRelType.ANTI) {
+			return false;
+		}
+		// all expressions in Project should be RexInputRef
+		for (RexNode p : project.getProjects()) {
+			if (!(p instanceof RexInputRef)) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	//~ Methods ----------------------------------------------------------------
+
+	public void onMatch(RelOptRuleCall call) {
+		LogicalJoin join = call.rel(0);
+		LogicalProject project = call.rel(1);
+
+		// convert the semi/anti join condition to reflect the LHS with the project
+		// pulled up
+		RexNode newCondition = adjustCondition(project, join);
+		Join newJoin = LogicalJoin.create(
+				project.getInput(), join.getRight(), newCondition, join.getVariablesSet(), join.getJoinType());
+
+		// Create the new projection. Note that the projection expressions
+		// are the same as the original because they only reference the LHS
+		// of the semi/anti join and the semi/anti join only projects out the LHS
+		final RelBuilder relBuilder = call.builder();
+		relBuilder.push(newJoin);
+		relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());
+
+		call.transformTo(relBuilder.build());
+	}
+
+	/**
+	 * Pulls the project above the semi/anti join and returns the resulting semi/anti join
+	 * condition. As a result, the semi/anti join condition should be modified such
+	 * that references to the LHS of a semi/anti join should now reference the
+	 * children of the project that's on the LHS.
+	 *
+	 * @param project LogicalProject on the LHS of the semi/anti join
+	 * @param join the semi/anti join
+	 * @return the modified semi/anti join condition
+	 */
+	private RexNode adjustCondition(LogicalProject project, Join join) {
+		// create two RexPrograms -- the bottom one representing a
+		// concatenation of the project and the RHS of the semi/anti join and the
+		// top one representing the semi/anti join condition
+
+		RexBuilder rexBuilder = project.getCluster().getRexBuilder();
+		RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
+		RelNode rightChild = join.getRight();
+
+		// for the bottom RexProgram, the input is a concatenation of the
+		// child of the project and the RHS of the semi/anti join
+		RelDataType bottomInputRowType =
+				SqlValidatorUtil.deriveJoinRowType(
+						project.getInput().getRowType(),
+						rightChild.getRowType(),
+						JoinRelType.INNER,
+						typeFactory,
+						null,
+						join.getSystemFieldList());
+		RexProgramBuilder bottomProgramBuilder =
+				new RexProgramBuilder(bottomInputRowType, rexBuilder);
+
+		// add the project expressions, then add input references for the RHS
+		// of the semi/anti join
+		for (Pair<RexNode, String> pair : project.getNamedProjects()) {
+			bottomProgramBuilder.addProject(pair.left, pair.right);
+		}
+		int nLeftFields = project.getInput().getRowType().getFieldCount();
+		List<RelDataTypeField> rightFields =
+				rightChild.getRowType().getFieldList();
+		int nRightFields = rightFields.size();
+		for (int i = 0; i < nRightFields; i++) {
+			final RelDataTypeField field = rightFields.get(i);
+			RexNode inputRef =
+					rexBuilder.makeInputRef(
+							field.getType(), i + nLeftFields);
+			bottomProgramBuilder.addProject(inputRef, field.getName());
+		}
+		RexProgram bottomProgram = bottomProgramBuilder.getProgram();
+
+		// input rowtype into the top program is the concatenation of the
+		// project and the RHS of the semi/anti join
+		RelDataType topInputRowType =
+				SqlValidatorUtil.deriveJoinRowType(
+						project.getRowType(),
+						rightChild.getRowType(),
+						JoinRelType.INNER,
+						typeFactory,
+						null,
+						join.getSystemFieldList());
+		RexProgramBuilder topProgramBuilder =
+				new RexProgramBuilder(
+						topInputRowType,
+						rexBuilder);
+		topProgramBuilder.addIdentity();
+		topProgramBuilder.addCondition(join.getCondition());
+		RexProgram topProgram = topProgramBuilder.getProgram();
+
+		// merge the programs and expand out the local references to form
+		// the new semi/anti join condition; it now references a concatenation of
+		// the project's child and the RHS of the semi/anti join
+		RexProgram mergedProgram =
+				RexProgramBuilder.mergePrograms(
+						topProgram,
+						bottomProgram,
+						rexBuilder);
+
+		return mergedProgram.expandLocalRef(
+				mergedProgram.getCondition());
+	}
+}
+
+// End FlinkSemiAntiJoinProjectTransposeRule.java
diff --git a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala
index bee709a..103b757 100644
--- a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala
+++ b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkBatchRuleSets.scala
@@ -166,6 +166,8 @@ object FlinkBatchRuleSets {
     // push all expressions to handle the time indicator correctly
     new FlinkProjectJoinTransposeRule(
       PushProjector.ExprCondition.FALSE, RelFactories.LOGICAL_BUILDER),
+    // push a projection to the children of a semi/anti Join
+    ProjectSemiAntiJoinTransposeRule.INSTANCE,
     // merge projections
     ProjectMergeRule.INSTANCE,
     // remove identity project
@@ -233,7 +235,12 @@ object FlinkBatchRuleSets {
     ProjectCalcMergeRule.INSTANCE,
     FilterToCalcRule.INSTANCE,
     ProjectToCalcRule.INSTANCE,
-    FlinkCalcMergeRule.INSTANCE
+    FlinkCalcMergeRule.INSTANCE,
+
+    // semi/anti join transpose rule
+    FlinkSemiAntiJoinJoinTransposeRule.INSTANCE,
+    FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+    FlinkSemiAntiJoinFilterTransposeRule.INSTANCE
   )
 
   /**
diff --git a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala
index fd8014b..9359ae1 100644
--- a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala
+++ b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/FlinkStreamRuleSets.scala
@@ -168,6 +168,8 @@ object FlinkStreamRuleSets {
     // push all expressions to handle the time indicator correctly
     new FlinkProjectJoinTransposeRule(
       PushProjector.ExprCondition.FALSE, RelFactories.LOGICAL_BUILDER),
+    // push a projection to the children of a semi/anti Join
+    ProjectSemiAntiJoinTransposeRule.INSTANCE,
     // merge projections
     ProjectMergeRule.INSTANCE,
     // remove identity project
@@ -220,7 +222,12 @@ object FlinkStreamRuleSets {
     ProjectCalcMergeRule.INSTANCE,
     FilterToCalcRule.INSTANCE,
     ProjectToCalcRule.INSTANCE,
-    FlinkCalcMergeRule.INSTANCE
+    FlinkCalcMergeRule.INSTANCE,
+
+    // semi/anti join transpose rule
+    FlinkSemiAntiJoinJoinTransposeRule.INSTANCE,
+    FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+    FlinkSemiAntiJoinFilterTransposeRule.INSTANCE
   )
 
   /**
diff --git a/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRule.scala b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRule.scala
new file mode 100644
index 0000000..09ee0f6
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRule.scala
@@ -0,0 +1,167 @@
+/*
+ * 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.flink.table.plan.rules.logical
+
+import org.apache.calcite.plan.RelOptRule._
+import org.apache.calcite.plan.{RelOptRule, RelOptRuleCall, RelOptUtil}
+import org.apache.calcite.rel.RelNode
+import org.apache.calcite.rel.`type`.{RelDataType, RelDataTypeFactory}
+import org.apache.calcite.rel.core.{Join, JoinRelType, Project}
+import org.apache.calcite.rel.logical.{LogicalJoin, LogicalProject}
+import org.apache.calcite.rex.{RexInputRef, RexNode, RexShuttle}
+import org.apache.calcite.tools.RelBuilder
+import org.apache.calcite.util.ImmutableBitSet
+import org.apache.calcite.util.mapping.Mappings
+
+import java.util
+import java.util.function.IntFunction
+
+import scala.collection.JavaConversions._
+
+/**
+  * Planner rule that pushes a [[Project]] down in a tree past a semi/anti [[Join]]
+  * by splitting the projection into a projection on top of left child of the Join.
+  */
+class ProjectSemiAntiJoinTransposeRule
+  extends RelOptRule(
+    operand(classOf[LogicalProject],
+      operand(classOf[LogicalJoin], any)),
+    "ProjectSemiAntiJoinTransposeRule") {
+
+
+  override def matches(call: RelOptRuleCall): Boolean = {
+    val join: LogicalJoin = call.rel(1)
+    join.getJoinType match {
+      case JoinRelType.SEMI | JoinRelType.ANTI => true
+      case _ => false
+    }
+  }
+
+  override def onMatch(call: RelOptRuleCall): Unit = {
+    val project: LogicalProject = call.rel(0)
+    val join: LogicalJoin = call.rel(1)
+
+    // 1. calculate every inputs reference fields
+    val joinCondFields = RelOptUtil.InputFinder.bits(join.getCondition)
+    val projectFields = RelOptUtil.InputFinder.bits(project.getProjects, null)
+    val allNeededFields = if (projectFields.isEmpty) {
+      // if project does not reference any input fields, at least one field needs to be output
+      joinCondFields.union(ImmutableBitSet.of(0))
+    } else {
+      joinCondFields.union(projectFields)
+    }
+
+    val leftFieldCount = join.getLeft.getRowType.getFieldCount
+    val allInputFieldCount = leftFieldCount + join.getRight.getRowType.getFieldCount
+    if (allNeededFields.equals(ImmutableBitSet.range(0, allInputFieldCount))) {
+      return
+    }
+
+    val leftNeededFields = ImmutableBitSet.range(0, leftFieldCount).intersect(allNeededFields)
+    val rightNeededFields = ImmutableBitSet.range(leftFieldCount, allInputFieldCount)
+      .intersect(allNeededFields)
+
+    // 2. new join inputs
+    val newLeftInput = createNewJoinInput(call.builder, join.getLeft, leftNeededFields, 0)
+    val newRightInput = createNewJoinInput(
+      call.builder, join.getRight, rightNeededFields, leftFieldCount)
+
+    // mapping origin field index to new field index,
+    // used to rewrite join condition and top project
+    val mapping = Mappings.target(
+      new IntFunction[Integer]() {
+        def apply(i: Int): Integer = allNeededFields.indexOf(i)
+      },
+      allInputFieldCount, allNeededFields.cardinality())
+
+    // 3. create new join
+    val newJoin = createNewJoin(join, mapping, newLeftInput, newRightInput)
+
+    // 4. create top project
+    val newProjects = createNewProjects(project, newJoin, mapping)
+    val topProject = call.builder
+      .push(newJoin)
+      .project(newProjects, project.getRowType.getFieldNames)
+      .build
+
+    call.transformTo(topProject)
+  }
+
+  private def createNewJoinInput(
+      relBuilder: RelBuilder,
+      originInput: RelNode,
+      inputNeededFields: ImmutableBitSet,
+      offset: Int): RelNode = {
+    val rexBuilder = originInput.getCluster.getRexBuilder
+    val typeBuilder = new RelDataTypeFactory.FieldInfoBuilder(relBuilder.getTypeFactory)
+    val newProjects: util.List[RexNode] = new util.ArrayList[RexNode]()
+    val newFieldNames: util.List[String] = new util.ArrayList[String]()
+    inputNeededFields.toList.foreach { i =>
+      newProjects.add(rexBuilder.makeInputRef(originInput, i - offset))
+      newFieldNames.add(originInput.getRowType.getFieldNames.get(i - offset))
+      typeBuilder.add(originInput.getRowType.getFieldList.get(i - offset))
+    }
+    relBuilder.push(originInput).project(newProjects, newFieldNames).build
+  }
+
+  private def createNewJoin(
+      originJoin: Join,
+      mapping: Mappings.TargetMapping,
+      newLeftInput: RelNode,
+      newRightInput: RelNode): Join = {
+    val newCondition = rewriteJoinCondition(originJoin, mapping)
+    LogicalJoin.create(newLeftInput, newRightInput, newCondition, originJoin.getVariablesSet,
+      originJoin.getJoinType)
+  }
+
+  private def rewriteJoinCondition(
+      originJoin: Join,
+      mapping: Mappings.TargetMapping): RexNode = {
+    val rexBuilder = originJoin.getCluster.getRexBuilder
+    val rexShuttle = new RexShuttle() {
+      override def visitInputRef(ref: RexInputRef): RexNode = {
+        val leftFieldCount = originJoin.getLeft.getRowType.getFieldCount
+        val fieldType: RelDataType = if (ref.getIndex < leftFieldCount) {
+          originJoin.getLeft.getRowType.getFieldList.get(ref.getIndex).getType
+        } else {
+          originJoin.getRight.getRowType.getFieldList.get(ref.getIndex - leftFieldCount).getType
+        }
+        rexBuilder.makeInputRef(fieldType, mapping.getTarget(ref.getIndex))
+      }
+    }
+    originJoin.getCondition.accept(rexShuttle)
+  }
+
+  private def createNewProjects(
+      originProject: Project,
+      newInput: RelNode,
+      mapping: Mappings.TargetMapping): Seq[RexNode] = {
+    val rexBuilder = originProject.getCluster.getRexBuilder
+    val projectShuffle = new RexShuttle() {
+      override def visitInputRef(ref: RexInputRef): RexNode = {
+        rexBuilder.makeInputRef(newInput, mapping.getTarget(ref.getIndex))
+      }
+    }
+    originProject.getProjects.map(_.accept(projectShuffle))
+  }
+}
+
+object ProjectSemiAntiJoinTransposeRule {
+  val INSTANCE = new ProjectSemiAntiJoinTransposeRule
+}
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml
index 9d9cd80..789b29d 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/BroadcastHashSemiAntiJoinTest.xml
@@ -177,8 +177,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -218,9 +218,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
          +- Exchange(distribution=[single])
             +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
                +- Calc(select=[true AS i])
-                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
-                     :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
-                     :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+                     :- Calc(select=[d])
+                     :  +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
                      +- Exchange(distribution=[broadcast])
                         +- Calc(select=[IS NOT NULL(m) AS $f0])
                            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -307,23 +308,23 @@ LogicalUnion(all=[false])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
-                        +- Exchange(distribution=[hash[e, f]])
-                           +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
-                              +- Union(all=[true], union=[e, f])
-                                 :- Calc(select=[e, f], where=[>(d, 10)])
-                                 :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                                 +- Calc(select=[j, k], where=[<(i, 100)])
-                                    +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+                     +- Exchange(distribution=[hash[e, f]])
+                        +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+                           +- Union(all=[true], union=[e, f])
+                              :- Calc(select=[e, f], where=[>(d, 10)])
+                              :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                              +- Calc(select=[j, k], where=[<(i, 100)])
+                                 +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -469,8 +470,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], isBroadcast=[true], build=[right])
-   :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], isBroadcast=[true], build=[right])
+   :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -595,8 +596,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], isBroadcast=[true], build=[right])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], isBroadcast=[true], build=[right])
+   :- Calc(select=[a, c])
+   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[d, k])
          +- HashJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], isBroadcast=[true], build=[left])
@@ -705,13 +707,12 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], isBroadcast=[true], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast=[true], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -770,9 +771,10 @@ LogicalProject(i=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], isBroadcast=[true], build=[right])
-   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], isBroadcast=[true], build=[right])
+   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+   :  :- Calc(select=[a, c])
+   :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :  +- Exchange(distribution=[broadcast])
    :     +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :        +- Exchange(distribution=[single])
@@ -891,8 +893,9 @@ LogicalProject(EXPR$0=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], isBroadcast=[true], build=[right])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], isBroadcast=[true], build=[right])
+   :- Calc(select=[a, b])
+   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[EXPR$0])
          +- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1002,9 +1005,10 @@ LogicalProject(j=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], isBroadcast=[true], build=[right])
-   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], isBroadcast=[true], build=[right])
+   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+   :  :- Calc(select=[a])
+   :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :  +- Exchange(distribution=[broadcast])
    :     +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :        +- Exchange(distribution=[single])
@@ -1043,8 +1047,9 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
 Calc(select=[b])
 +- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
    :- Calc(select=[b])
-   :  +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast=[true], build=[right])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], isBroadcast=[true], build=[right])
+   :     :- Calc(select=[a, b])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- Calc(select=[d], where=[>(e, 10)])
    :           +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1079,8 +1084,8 @@ LogicalProject(e=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[s])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], isBroadcast=[true], build=[right])
-   :- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], isBroadcast=[true], build=[right])
+   :- Calc(select=[s, $f3], where=[>($f2, 2)])
    :  +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
    :     +- Exchange(distribution=[hash[b]])
    :        +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1281,8 +1286,9 @@ LogicalUnion(all=[false])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], isBroadcast=[true], build=[right])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], isBroadcast=[true], build=[right])
+   :- Calc(select=[a, b])
+   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
          +- Exchange(distribution=[hash[e]])
@@ -1316,16 +1322,16 @@ LogicalTableScan(table=[[t, source: [TestTableSource(i, j, k)]]])
 HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast=[true], build=[right])
 :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[broadcast])
-   +- Calc(select=[d])
-      +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-         +- Exchange(distribution=[broadcast])
-            +- Calc(select=[IS NOT NULL(m) AS $f0])
-               +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-                  +- Exchange(distribution=[single])
-                     +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                        +- Calc(select=[true AS i])
-                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+   +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+      :- Calc(select=[d])
+      :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- Exchange(distribution=[broadcast])
+         +- Calc(select=[IS NOT NULL(m) AS $f0])
+            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+               +- Exchange(distribution=[single])
+                  +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+                     +- Calc(select=[true AS i])
+                        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -1395,19 +1401,19 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[right])
-:- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[right])
-:  :- HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[left])
-:  :  :- Exchange(distribution=[broadcast])
-:  :  :  +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
-:  :  :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-:  :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-:  +- Exchange(distribution=[broadcast])
-:     +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-:        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[broadcast])
-   +- Calc(select=[i], where=[<(j, 100)])
-      +- Reused(reference_id=[1])
+HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], isBroadcast=[true], build=[left])
+:- Exchange(distribution=[broadcast])
+:  +- HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], isBroadcast=[true], build=[right])
+:     :- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], isBroadcast=[true], build=[right])
+:     :  :- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
+:     :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+:     :  +- Exchange(distribution=[broadcast])
+:     :     +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+:     :        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+:     +- Exchange(distribution=[broadcast])
+:        +- Calc(select=[i], where=[<(j, 100)])
+:           +- Reused(reference_id=[1])
++- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -1564,8 +1570,9 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], isBroadcast
 :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[broadcast])
    +- Calc(select=[d])
-      +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], isBroadcast=[true], build=[right])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], isBroadcast=[true], build=[right])
+         :- Calc(select=[d, e])
+         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[broadcast])
             +- Calc(select=[j])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1657,8 +1664,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -1804,8 +1811,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], isBroadcast=[true], build=[right])
-   :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], isBroadcast=[true], build=[right])
+   :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -1837,8 +1844,8 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], isBroadcast=[true], build=[right])
-   :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], isBroadcast=[true], build=[right])
+   :- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
    :  +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], isBroadcast=[true], build=[right])
    :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
    :     :  :- Calc(select=[a, b, c, c0, ck, i0])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml
index c967fb6..09a0420 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/NestedLoopSemiAntiJoinTest.xml
@@ -147,14 +147,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- LocalHashAggregate(select=[])
-         +- Calc(select=[])
-            +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- LocalHashAggregate(select=[])
+      +- Calc(select=[])
+         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -228,8 +227,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -260,22 +259,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- NestedLoopJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
-                        :- Exchange(distribution=[single])
-                        :  +- Calc(select=[e])
-                        :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                        +- Exchange(distribution=[single])
-                           +- Calc(select=[j], where=[>(i, 10)])
-                              +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- NestedLoopJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
+                     :- Exchange(distribution=[single])
+                     :  +- Calc(select=[e])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                     +- Exchange(distribution=[single])
+                        +- Calc(select=[j], where=[>(i, 10)])
+                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -307,9 +306,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
          +- Exchange(distribution=[single])
             +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
                +- Calc(select=[true AS i])
-                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
-                     :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
-                     :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+                     :- Calc(select=[d])
+                     :  +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
                      +- Exchange(distribution=[broadcast])
                         +- Calc(select=[IS NOT NULL(m) AS $f0])
                            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -396,23 +396,23 @@ LogicalUnion(all=[false])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
-                        +- Exchange(distribution=[hash[e, f]])
-                           +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
-                              +- Union(all=[true], union=[e, f])
-                                 :- Calc(select=[e, f], where=[>(d, 10)])
-                                 :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                                 +- Calc(select=[j, k], where=[<(i, 100)])
-                                    +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+                     +- Exchange(distribution=[hash[e, f]])
+                        +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+                           +- Union(all=[true], union=[e, f])
+                              :- Calc(select=[e, f], where=[>(d, 10)])
+                              :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                              +- Calc(select=[j, k], where=[<(i, 100)])
+                                 +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -614,8 +614,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
-   :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
+   :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -670,8 +670,8 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[b, c, $f3], build=[right])
+   :- Calc(select=[b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
    :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
    :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
    :     :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
@@ -786,8 +786,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], build=[right])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], build=[right])
+   :- Calc(select=[a, c])
+   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[d, k])
          +- NestedLoopJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], build=[left])
@@ -896,13 +897,12 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -961,9 +961,10 @@ LogicalProject(i=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], build=[right])
-   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], build=[right])
+   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+   :  :- Calc(select=[a, c])
+   :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :  +- Exchange(distribution=[broadcast])
    :     +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :        +- Exchange(distribution=[single])
@@ -1082,8 +1083,9 @@ LogicalProject(EXPR$0=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], build=[right])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], build=[right])
+   :- Calc(select=[a, b])
+   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[EXPR$0])
          +- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1194,11 +1196,12 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
-   :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
-   :     :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[b, $f3], build=[right])
+   :- Calc(select=[b, CASE(AND(<>(c, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, i], build=[right])
+   :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c], build=[right], singleRowJoin=[true])
+   :     :  :- Calc(select=[a, b])
+   :     :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     :  +- Exchange(distribution=[broadcast])
    :     :     +- Calc(select=[c])
    :     :        +- HashAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
@@ -1241,9 +1244,10 @@ LogicalProject(j=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], build=[right])
-   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], build=[right])
+   :- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+   :  :- Calc(select=[a])
+   :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :  +- Exchange(distribution=[broadcast])
    :     +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :        +- Exchange(distribution=[single])
@@ -1282,8 +1286,9 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
 Calc(select=[b])
 +- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
    :- Calc(select=[b])
-   :  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], build=[right])
+   :     :- Calc(select=[a, b])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- Calc(select=[d], where=[>(e, 10)])
    :           +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1318,8 +1323,8 @@ LogicalProject(e=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[s])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], build=[right])
-   :- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], build=[right])
+   :- Calc(select=[s, $f3], where=[>($f2, 2)])
    :  +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
    :     +- Exchange(distribution=[hash[b]])
    :        +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1355,8 +1360,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c], build=[right])
+   :- Calc(select=[a, c])
+   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[d])
          +- NestedLoopJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0], build=[right])
@@ -1558,8 +1564,9 @@ LogicalUnion(all=[false])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], build=[right])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], build=[right])
+   :- Calc(select=[a, b])
+   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
          +- Exchange(distribution=[hash[e]])
@@ -1628,16 +1635,16 @@ LogicalTableScan(table=[[t, source: [TestTableSource(i, j, k)]]])
 NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
 :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[broadcast])
-   +- Calc(select=[d])
-      +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-         +- Exchange(distribution=[broadcast])
-            +- Calc(select=[IS NOT NULL(m) AS $f0])
-               +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-                  +- Exchange(distribution=[single])
-                     +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                        +- Calc(select=[true AS i])
-                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+   +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+      :- Calc(select=[d])
+      :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- Exchange(distribution=[broadcast])
+         +- Calc(select=[IS NOT NULL(m) AS $f0])
+            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+               +- Exchange(distribution=[single])
+                  +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+                     +- Calc(select=[true AS i])
+                        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -1839,8 +1846,9 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build
 :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[broadcast])
    +- Calc(select=[d])
-      +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], build=[right])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], build=[right])
+         :- Calc(select=[d, e])
+         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[broadcast])
             +- Calc(select=[j])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1868,19 +1876,19 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], build=[right])
-:- NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], build=[right])
-:  :- NestedLoopJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
-:  :  :- Exchange(distribution=[broadcast])
-:  :  :  +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
-:  :  :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-:  :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-:  +- Exchange(distribution=[broadcast])
-:     +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-:        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[broadcast])
-   +- Calc(select=[i], where=[<(j, 100)])
-      +- Reused(reference_id=[1])
+NestedLoopJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
+:- Exchange(distribution=[broadcast])
+:  +- NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], build=[right])
+:     :- NestedLoopJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], build=[right])
+:     :  :- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
+:     :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+:     :  +- Exchange(distribution=[broadcast])
+:     :     +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+:     :        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+:     +- Exchange(distribution=[broadcast])
+:        +- Calc(select=[i], where=[<(j, 100)])
+:           +- Reused(reference_id=[1])
++- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -1954,8 +1962,9 @@ NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d
 :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[broadcast])
    +- Calc(select=[d])
-      +- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e, f], build=[right])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e], build=[right])
+         :- Calc(select=[d, e])
+         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[broadcast])
             +- Calc(select=[j, i])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -2002,14 +2011,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- LocalHashAggregate(select=[])
-         +- Calc(select=[])
-            +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- LocalHashAggregate(select=[])
+      +- Calc(select=[])
+         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2053,8 +2061,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -2200,8 +2208,8 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
-   :- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
+   :- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -2233,8 +2241,8 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], build=[right])
+   :- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
    :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], build=[right])
    :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
    :     :  :- Calc(select=[a, b, c, c0, ck, i0])
@@ -2340,13 +2348,12 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2473,14 +2480,15 @@ LogicalProject(e=[$1], d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c, c0, ck, i0, c1, ck0, j, i], build=[right])
-   :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
-   :     :  :- Calc(select=[a, b, c, c0, ck, i0])
-   :     :  :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, c0, ck, i, i0], build=[right])
-   :     :  :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck], build=[right], singleRowJoin=[true])
-   :     :  :     :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[b, $f3], build=[right])
+   :- Calc(select=[b, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c, 0), AND(<>(c, 0), IS NULL(i), >=(ck0, c), IS NOT NULL(a))), 2, 3) AS $f3])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c0, ck, i0, c, ck0, j, i], build=[right])
+   :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c0, ck, i0, c, ck0], build=[right], singleRowJoin=[true])
+   :     :  :- Calc(select=[a, b, c AS c0, ck, i0])
+   :     :  :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, ck, i, i0], build=[right])
+   :     :  :     :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, ck], build=[right], singleRowJoin=[true])
+   :     :  :     :  :- Calc(select=[a, b])
+   :     :  :     :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     :  :     :  +- Exchange(distribution=[broadcast])
    :     :  :     :     +- SortAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
    :     :  :     :        +- Exchange(distribution=[single])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml
index 2a962ba..e8efee0 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SemiAntiJoinTest.xml
@@ -149,14 +149,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- LocalHashAggregate(select=[])
-         +- Calc(select=[])
-            +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- LocalHashAggregate(select=[])
+      +- Calc(select=[])
+         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -232,8 +231,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -264,22 +263,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
-                        :- Exchange(distribution=[hash[e]])
-                        :  +- Calc(select=[e])
-                        :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                        +- Exchange(distribution=[hash[j]])
-                           +- Calc(select=[j], where=[>(i, 10)])
-                              +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
+                     :- Exchange(distribution=[hash[e]])
+                     :  +- Calc(select=[e])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                     +- Exchange(distribution=[hash[j]])
+                        +- Calc(select=[j], where=[>(i, 10)])
+                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -311,9 +310,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
          +- Exchange(distribution=[single])
             +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
                +- Calc(select=[true AS i])
-                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
-                     :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
-                     :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+                     :- Calc(select=[d])
+                     :  +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
                      +- Exchange(distribution=[broadcast])
                         +- Calc(select=[IS NOT NULL(m) AS $f0])
                            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -400,23 +400,23 @@ LogicalUnion(all=[false])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
-                        +- Exchange(distribution=[hash[e, f]])
-                           +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
-                              +- Union(all=[true], union=[e, f])
-                                 :- Calc(select=[e, f], where=[>(d, 10)])
-                                 :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                                 +- Calc(select=[j, k], where=[<(i, 100)])
-                                    +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+                     +- Exchange(distribution=[hash[e, f]])
+                        +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+                           +- Union(all=[true], union=[e, f])
+                              :- Calc(select=[e, f], where=[>(d, 10)])
+                              :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                              +- Calc(select=[j, k], where=[<(i, 100)])
+                                 +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -626,9 +626,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
    :- Exchange(distribution=[hash[$f3, $f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0, e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -684,9 +684,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[a, b, c, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[b, c, $f3], build=[left])
    :- Exchange(distribution=[hash[$f3, c]])
-   :  +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+   :  +- Calc(select=[b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
    :     +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
    :        :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
    :        :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
@@ -805,9 +805,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], build=[right])
    :- Exchange(distribution=[hash[a, c]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d, k]])
       +- Calc(select=[d, k])
          +- HashJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], build=[left])
@@ -919,14 +920,13 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], build=[right])
-   :- Exchange(distribution=[hash[a]])
-   :  +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[hash[d]])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+:- Exchange(distribution=[hash[a]])
+:  +- Calc(select=[a, b, c], where=[>(b, 10)])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -986,10 +986,11 @@ LogicalProject(i=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], build=[right])
    :- Exchange(distribution=[hash[EXPR$0, c]])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+   :     :- Calc(select=[a, c])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -1112,9 +1113,10 @@ LogicalProject(EXPR$0=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], build=[right])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0]])
       +- Calc(select=[EXPR$0])
          +- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1228,12 +1230,13 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[a, b, c, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[b, $f3], build=[left])
    :- Exchange(distribution=[hash[$f3]])
-   :  +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
-   :     +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i], build=[right])
-   :        :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0], build=[right], singleRowJoin=[true])
-   :        :  :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[b, CASE(AND(<>(c, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+   :     +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, i], build=[right])
+   :        :- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c], build=[right], singleRowJoin=[true])
+   :        :  :- Calc(select=[a, b])
+   :        :  :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :        :  +- Exchange(distribution=[broadcast])
    :        :     +- Calc(select=[c])
    :        :        +- HashAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
@@ -1276,10 +1279,11 @@ LogicalProject(j=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], build=[right])
    :- Exchange(distribution=[hash[EXPR$0]])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+   :     :- Calc(select=[a])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -1318,9 +1322,10 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
 Calc(select=[b])
 +- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
    :- Calc(select=[b])
-   :  +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+   :  +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], build=[right])
    :     :- Exchange(distribution=[hash[a]])
-   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :     :  +- Calc(select=[a, b])
+   :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[hash[d]])
    :        +- Calc(select=[d], where=[>(e, 10)])
    :           +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1355,9 +1360,9 @@ LogicalProject(e=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[s])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], build=[left])
    :- Exchange(distribution=[hash[$f3]])
-   :  +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+   :  +- Calc(select=[s, $f3], where=[>($f2, 2)])
    :     +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
    :        +- Exchange(distribution=[hash[b]])
    :           +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1393,9 +1398,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c], build=[right])
    :- Exchange(distribution=[hash[a]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d]])
       +- Calc(select=[d])
          +- HashJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0], build=[right])
@@ -1602,9 +1608,10 @@ LogicalUnion(all=[false])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], build=[right])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
          +- Exchange(distribution=[hash[e]])
@@ -1674,16 +1681,16 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
 :- Exchange(distribution=[hash[a]])
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
-   +- Calc(select=[d])
-      +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-         +- Exchange(distribution=[broadcast])
-            +- Calc(select=[IS NOT NULL(m) AS $f0])
-               +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-                  +- Exchange(distribution=[single])
-                     +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                        +- Calc(select=[true AS i])
-                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+   +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+      :- Calc(select=[d])
+      :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- Exchange(distribution=[broadcast])
+         +- Calc(select=[IS NOT NULL(m) AS $f0])
+            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+               +- Exchange(distribution=[single])
+                  +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+                     +- Calc(select=[true AS i])
+                        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -1895,9 +1902,10 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
    +- Calc(select=[d])
-      +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], build=[right])
+      +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], build=[right])
          :- Exchange(distribution=[hash[e]])
-         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+         :  +- Calc(select=[d, e])
+         :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[hash[j]])
             +- Calc(select=[j])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1925,22 +1933,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], build=[right])
+HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
 :- Exchange(distribution=[hash[a]])
-:  +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], build=[right])
-:     :- Exchange(distribution=[hash[b]])
-:     :  +- HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
-:     :     :- Exchange(distribution=[hash[a]])
+:  +- HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], build=[right])
+:     :- Exchange(distribution=[hash[a]])
+:     :  +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], build=[right])
+:     :     :- Exchange(distribution=[hash[b]])
 :     :     :  +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
 :     :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-:     :     +- Exchange(distribution=[hash[d]])
-:     :        +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-:     +- Exchange(distribution=[hash[j]])
-:        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-:           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
-   +- Calc(select=[i], where=[<(j, 100)])
-      +- Reused(reference_id=[1])
+:     :     +- Exchange(distribution=[hash[j]])
+:     :        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+:     :           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+:     +- Exchange(distribution=[hash[i]])
+:        +- Calc(select=[i], where=[<(j, 100)])
+:           +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+   +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2015,9 +2023,10 @@ NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d
 :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[broadcast])
    +- Calc(select=[d])
-      +- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e, f], build=[right])
+      +- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e], build=[left])
          :- Exchange(distribution=[hash[d]])
-         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+         :  +- Calc(select=[d, e])
+         :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[hash[i]])
             +- Calc(select=[j, i])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -2064,14 +2073,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- LocalHashAggregate(select=[])
-         +- Calc(select=[])
-            +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[true], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[<(a, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- LocalHashAggregate(select=[])
+      +- Calc(select=[])
+         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2116,8 +2124,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -2266,9 +2274,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
    :- Exchange(distribution=[hash[$f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -2300,9 +2308,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], build=[right])
    :- Exchange(distribution=[hash[c]])
-   :  +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+   :  +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
    :     +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], build=[right])
    :        :- Exchange(distribution=[hash[a]])
    :        :  +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
@@ -2411,13 +2419,12 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+NestedLoopJoin(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c], build=[right])
+:- Calc(select=[a, b, c], where=[>(b, 10)])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2546,16 +2553,17 @@ LogicalProject(e=[$1], d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[a, b, c, $f3], build=[right])
-   :- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
-   :  +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c, c0, ck, i0, c1, ck0, j, i], build=[right])
++- NestedLoopJoin(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[b, $f3], build=[right])
+   :- Calc(select=[b, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c, 0), AND(<>(c, 0), IS NULL(i), >=(ck0, c), IS NOT NULL(a))), 2, 3) AS $f3])
+   :  +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c0, ck, i0, c, ck0, j, i], build=[right])
    :     :- Exchange(distribution=[hash[a]])
-   :     :  +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
-   :     :     :- Calc(select=[a, b, c, c0, ck, i0])
-   :     :     :  +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, c0, ck, i, i0], build=[right])
+   :     :  +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c0, ck, i0, c, ck0], build=[right], singleRowJoin=[true])
+   :     :     :- Calc(select=[a, b, c AS c0, ck, i0])
+   :     :     :  +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, ck, i, i0], build=[right])
    :     :     :     :- Exchange(distribution=[hash[a]])
-   :     :     :     :  +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck], build=[right], singleRowJoin=[true])
-   :     :     :     :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :     :     :     :  +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, ck], build=[right], singleRowJoin=[true])
+   :     :     :     :     :- Calc(select=[a, b])
+   :     :     :     :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     :     :     :     +- Exchange(distribution=[broadcast])
    :     :     :     :        +- SortAggregate(isMerge=[true], select=[Final_COUNT(count1$0) AS c, Final_COUNT(count$1) AS ck])
    :     :     :     :           +- Exchange(distribution=[single])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml
index c5ac381..bd57fc8 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/ShuffledHashSemiAntiJoinTest.xml
@@ -154,8 +154,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -186,22 +186,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
-                        :- Exchange(distribution=[hash[e]])
-                        :  +- Calc(select=[e])
-                        :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                        +- Exchange(distribution=[hash[j]])
-                           +- Calc(select=[j], where=[>(i, 10)])
-                              +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- HashJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j], build=[right])
+                     :- Exchange(distribution=[hash[e]])
+                     :  +- Calc(select=[e])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                     +- Exchange(distribution=[hash[j]])
+                        +- Calc(select=[j], where=[>(i, 10)])
+                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -233,9 +233,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
          +- Exchange(distribution=[single])
             +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
                +- Calc(select=[true AS i])
-                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
-                     :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
-                     :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+                     :- Calc(select=[d])
+                     :  +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
                      +- Exchange(distribution=[broadcast])
                         +- Calc(select=[IS NOT NULL(m) AS $f0])
                            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -322,23 +323,23 @@ LogicalUnion(all=[false])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
-                        +- Exchange(distribution=[hash[e, f]])
-                           +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
-                              +- Union(all=[true], union=[e, f])
-                                 :- Calc(select=[e, f], where=[>(d, 10)])
-                                 :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                                 +- Calc(select=[j, k], where=[<(i, 100)])
-                                    +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+                     +- Exchange(distribution=[hash[e, f]])
+                        +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+                           +- Union(all=[true], union=[e, f])
+                              :- Calc(select=[e, f], where=[>(d, 10)])
+                              :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                              +- Calc(select=[j, k], where=[<(i, 100)])
+                                 +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -490,9 +491,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
    :- Exchange(distribution=[hash[$f3, $f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0, e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -622,9 +623,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c], build=[right])
    :- Exchange(distribution=[hash[a, c]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d, k]])
       +- Calc(select=[d, k])
          +- HashJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k], build=[left])
@@ -708,14 +710,13 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3], build=[right])
-   :- Exchange(distribution=[hash[a]])
-   :  +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[hash[d]])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+:- Exchange(distribution=[hash[a]])
+:  +- Calc(select=[a, b, c], where=[>(b, 10)])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -775,10 +776,11 @@ LogicalProject(i=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0], build=[right])
    :- Exchange(distribution=[hash[EXPR$0, c]])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+   :     :- Calc(select=[a, c])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -901,9 +903,10 @@ LogicalProject(EXPR$0=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b], build=[right])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0]])
       +- Calc(select=[EXPR$0])
          +- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1016,10 +1019,11 @@ LogicalProject(j=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0], build=[right])
    :- Exchange(distribution=[hash[EXPR$0]])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+   :     :- Calc(select=[a])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -1058,9 +1062,10 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
 Calc(select=[b])
 +- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
    :- Calc(select=[b])
-   :  +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
+   :  +- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b], build=[right])
    :     :- Exchange(distribution=[hash[a]])
-   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :     :  +- Calc(select=[a, b])
+   :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[hash[d]])
    :        +- Calc(select=[d], where=[>(e, 10)])
    :           +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1095,9 +1100,9 @@ LogicalProject(e=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[s])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3], build=[left])
++- HashJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3], build=[left])
    :- Exchange(distribution=[hash[$f3]])
-   :  +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+   :  +- Calc(select=[s, $f3], where=[>($f2, 2)])
    :     +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
    :        +- Exchange(distribution=[hash[b]])
    :           +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1133,9 +1138,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c], build=[right])
    :- Exchange(distribution=[hash[a]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d]])
       +- Calc(select=[d])
          +- HashJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0], build=[right])
@@ -1315,9 +1321,10 @@ LogicalUnion(all=[false])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c], build=[right])
++- HashJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b], build=[right])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
          +- Exchange(distribution=[hash[e]])
@@ -1352,16 +1359,16 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
 :- Exchange(distribution=[hash[a]])
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
-   +- Calc(select=[d])
-      +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-         +- Exchange(distribution=[broadcast])
-            +- Calc(select=[IS NOT NULL(m) AS $f0])
-               +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-                  +- Exchange(distribution=[single])
-                     +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                        +- Calc(select=[true AS i])
-                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+   +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+      :- Calc(select=[d])
+      :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- Exchange(distribution=[broadcast])
+         +- Calc(select=[IS NOT NULL(m) AS $f0])
+            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+               +- Exchange(distribution=[single])
+                  +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+                     +- Calc(select=[true AS i])
+                        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -1432,22 +1439,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f], build=[right])
+HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
 :- Exchange(distribution=[hash[a]])
-:  +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f], build=[right])
-:     :- Exchange(distribution=[hash[b]])
-:     :  +- HashJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f], build=[left])
-:     :     :- Exchange(distribution=[hash[a]])
+:  +- HashJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c], build=[right])
+:     :- Exchange(distribution=[hash[a]])
+:     :  +- HashJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c], build=[right])
+:     :     :- Exchange(distribution=[hash[b]])
 :     :     :  +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
 :     :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-:     :     +- Exchange(distribution=[hash[d]])
-:     :        +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-:     +- Exchange(distribution=[hash[j]])
-:        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-:           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
-   +- Calc(select=[i], where=[<(j, 100)])
-      +- Reused(reference_id=[1])
+:     :     +- Exchange(distribution=[hash[j]])
+:     :        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+:     :           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+:     +- Exchange(distribution=[hash[i]])
+:        +- Calc(select=[i], where=[<(j, 100)])
+:           +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+   +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -1613,9 +1620,10 @@ HashJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c], build=[righ
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
    +- Calc(select=[d])
-      +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f], build=[right])
+      +- HashJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e], build=[right])
          :- Exchange(distribution=[hash[e]])
-         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+         :  +- Calc(select=[d, e])
+         :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[hash[j]])
             +- Calc(select=[j])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1709,8 +1717,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -1859,9 +1867,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4], build=[right])
    :- Exchange(distribution=[hash[$f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -1893,9 +1901,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3], build=[right])
++- HashJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3], build=[right])
    :- Exchange(distribution=[hash[c]])
-   :  +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+   :  +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
    :     +- HashJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i], build=[right])
    :        :- Exchange(distribution=[hash[a]])
    :        :  +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml
index 2495488..cba2428 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/batch/sql/join/SortMergeSemiAntiJoinTest.xml
@@ -182,8 +182,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -214,22 +214,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- SortMergeJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
-                        :- Exchange(distribution=[hash[e]])
-                        :  +- Calc(select=[e])
-                        :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                        +- Exchange(distribution=[hash[j]])
-                           +- Calc(select=[j], where=[>(i, 10)])
-                              +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[c], build=[right], singleRowJoin=[true])
+:- Calc(select=[c])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- SortMergeJoin(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
+                     :- Exchange(distribution=[hash[e]])
+                     :  +- Calc(select=[e])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                     +- Exchange(distribution=[hash[j]])
+                        +- Calc(select=[j], where=[>(i, 10)])
+                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -261,9 +261,10 @@ NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[ri
          +- Exchange(distribution=[single])
             +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
                +- Calc(select=[true AS i])
-                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0], build=[right], singleRowJoin=[true])
-                     :- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
-                     :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                  +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+                     :- Calc(select=[d])
+                     :  +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
                      +- Exchange(distribution=[broadcast])
                         +- Calc(select=[IS NOT NULL(m) AS $f0])
                            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
@@ -350,23 +351,23 @@ LogicalUnion(all=[false])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[broadcast])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-            +- Exchange(distribution=[single])
-               +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                  +- Calc(select=[true AS i])
-                     +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
-                        +- Exchange(distribution=[hash[e, f]])
-                           +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
-                              +- Union(all=[true], union=[e, f])
-                                 :- Calc(select=[e, f], where=[>(d, 10)])
-                                 :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                                 +- Calc(select=[j, k], where=[<(i, 100)])
-                                    +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a], build=[right], singleRowJoin=[true])
+:- Calc(select=[a])
+:  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[broadcast])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+         +- Exchange(distribution=[single])
+            +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+               +- Calc(select=[true AS i])
+                  +- HashAggregate(isMerge=[true], groupBy=[e, f], select=[e, f])
+                     +- Exchange(distribution=[hash[e, f]])
+                        +- LocalHashAggregate(groupBy=[e, f], select=[e, f])
+                           +- Union(all=[true], union=[e, f])
+                              :- Calc(select=[e, f], where=[>(d, 10)])
+                              :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                              +- Calc(select=[j, k], where=[<(i, 100)])
+                                 +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -518,9 +519,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4])
    :- Exchange(distribution=[hash[$f3, $f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0, e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -650,9 +651,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c])
    :- Exchange(distribution=[hash[a, c]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d, k]])
       +- Calc(select=[d, k])
          +- SortMergeJoin(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k])
@@ -765,14 +767,13 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3])
-   :- Exchange(distribution=[hash[a]])
-   :  +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[hash[d]])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+:- Exchange(distribution=[hash[a]])
+:  +- Calc(select=[a, b, c], where=[>(b, 10)])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -832,10 +833,11 @@ LogicalProject(i=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0])
    :- Exchange(distribution=[hash[EXPR$0, c]])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0], build=[right], singleRowJoin=[true])
+   :     :- Calc(select=[a, c])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- SortAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -958,9 +960,10 @@ LogicalProject(EXPR$0=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0]])
       +- Calc(select=[EXPR$0])
          +- HashAggregate(isMerge=[true], groupBy=[f], select=[f, Final_MAX(max$0) AS EXPR$0])
@@ -1073,10 +1076,11 @@ LogicalProject(j=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0])
    :- Exchange(distribution=[hash[EXPR$0]])
-   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0], build=[right], singleRowJoin=[true])
-   :     :- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- NestedLoopJoin(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0], build=[right], singleRowJoin=[true])
+   :     :- Calc(select=[a])
+   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[broadcast])
    :        +- HashAggregate(isMerge=[true], select=[Final_MAX(max$0) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -1115,9 +1119,10 @@ LogicalProject(EXPR$0=[*(0.5:DECIMAL(2, 1), $0)])
 Calc(select=[b])
 +- NestedLoopJoin(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0], build=[right], singleRowJoin=[true])
    :- Calc(select=[b])
-   :  +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+   :  +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b])
    :     :- Exchange(distribution=[hash[a]])
-   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :     :  +- Calc(select=[a, b])
+   :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[hash[d]])
    :        +- Calc(select=[d], where=[>(e, 10)])
    :           +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1152,9 +1157,9 @@ LogicalProject(e=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[s])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3])
    :- Exchange(distribution=[hash[$f3]])
-   :  +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+   :  +- Calc(select=[s, $f3], where=[>($f2, 2)])
    :     +- HashAggregate(isMerge=[true], groupBy=[b], select=[b, Final_SUM(sum$0) AS s, Final_COUNT(count1$1) AS $f2, Final_MAX(max$2) AS $f3])
    :        +- Exchange(distribution=[hash[b]])
    :           +- LocalHashAggregate(groupBy=[b], select=[b, Partial_SUM(a) AS sum$0, Partial_COUNT(*) AS count1$1, Partial_MAX(b) AS max$2])
@@ -1190,9 +1195,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c])
    :- Exchange(distribution=[hash[a]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d]])
       +- Calc(select=[d])
          +- SortMergeJoin(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0])
@@ -1400,9 +1406,10 @@ LogicalUnion(all=[false])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c])
++- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- HashAggregate(isMerge=[true], groupBy=[e], select=[e])
          +- Exchange(distribution=[hash[e]])
@@ -1437,16 +1444,16 @@ SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
 :- Exchange(distribution=[hash[a]])
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
-   +- Calc(select=[d])
-      +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f], build=[right], singleRowJoin=[true])
-         :- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-         +- Exchange(distribution=[broadcast])
-            +- Calc(select=[IS NOT NULL(m) AS $f0])
-               +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
-                  +- Exchange(distribution=[single])
-                     +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
-                        +- Calc(select=[true AS i])
-                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+   +- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[d], build=[right], singleRowJoin=[true])
+      :- Calc(select=[d])
+      :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- Exchange(distribution=[broadcast])
+         +- Calc(select=[IS NOT NULL(m) AS $f0])
+            +- HashAggregate(isMerge=[true], select=[Final_MIN(min$0) AS m])
+               +- Exchange(distribution=[single])
+                  +- LocalHashAggregate(select=[Partial_MIN(i) AS min$0])
+                     +- Calc(select=[true AS i])
+                        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -1517,22 +1524,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-SortMergeJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f])
+SortMergeJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
 :- Exchange(distribution=[hash[a]])
-:  +- SortMergeJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f])
-:     :- Exchange(distribution=[hash[b]])
-:     :  +- SortMergeJoin(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
-:     :     :- Exchange(distribution=[hash[a]])
+:  +- SortMergeJoin(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c])
+:     :- Exchange(distribution=[hash[a]])
+:     :  +- SortMergeJoin(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c])
+:     :     :- Exchange(distribution=[hash[b]])
 :     :     :  +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
 :     :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-:     :     +- Exchange(distribution=[hash[d]])
-:     :        +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-:     +- Exchange(distribution=[hash[j]])
-:        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-:           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
-   +- Calc(select=[i], where=[<(j, 100)])
-      +- Reused(reference_id=[1])
+:     :     +- Exchange(distribution=[hash[j]])
+:     :        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+:     :           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+:     +- Exchange(distribution=[hash[i]])
+:        +- Calc(select=[i], where=[<(j, 100)])
+:           +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+   +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -1698,9 +1705,10 @@ SortMergeJoin(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
    +- Calc(select=[d])
-      +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f])
+      +- SortMergeJoin(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e])
          :- Exchange(distribution=[hash[e]])
-         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+         :  +- Calc(select=[d, e])
+         :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[hash[j]])
             +- Calc(select=[j])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1794,8 +1802,8 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c], build=[right], singleRowJoin=[true])
-   :- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
++- NestedLoopJoin(joinType=[LeftSemiJoin], where=[$f0], select=[a, c], build=[right], singleRowJoin=[true])
+   :- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[broadcast])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -1944,9 +1952,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4])
++- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4])
    :- Exchange(distribution=[hash[$f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -1978,9 +1986,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3])
++- SortMergeJoin(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3])
    :- Exchange(distribution=[hash[c]])
-   :  +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+   :  +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
    :     +- SortMergeJoin(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i])
    :        :- Exchange(distribution=[hash[a]])
    :        :  +- NestedLoopJoin(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0], build=[right], singleRowJoin=[true])
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.xml
new file mode 100644
index 0000000..de2084b
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.xml
@@ -0,0 +1,79 @@
+<?xml version="1.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.
+-->
+<Root>
+  <TestCase name="testAntiJoinFilterTranspose">
+    <Resource name="sql">
+      <![CDATA[
+SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+    WHERE b NOT IN (SELECT e FROM MyTable2)
+      ]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[NOT(IN($1, {
+LogicalProject(e=[$1])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2])
+      +- LogicalFilter(condition=[>($0, 10)])
+         +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[>($0, 10)])
+   +- LogicalJoin(condition=[OR(=($1, $3), IS NULL($1), IS NULL($3))], joinType=[anti])
+      :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+      +- LogicalProject(e=[$1])
+         +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testSemiJoinFilterTranspose">
+    <Resource name="sql">
+      <![CDATA[
+SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+    WHERE b IN (SELECT e FROM MyTable2)
+      ]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[IN($1, {
+LogicalProject(e=[$1])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2])
+      +- LogicalFilter(condition=[>($0, 10)])
+         +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[>($0, 10)])
+   +- LogicalJoin(condition=[=($1, $3)], joinType=[semi])
+      :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+      +- LogicalProject(e=[$1])
+         +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.xml
new file mode 100644
index 0000000..6bece3e
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.xml
@@ -0,0 +1,1135 @@
+<?xml version="1.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.
+-->
+<Root>
+  <TestCase name="testEXISTS_EquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[<($1, 50)])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[$6], joinType=[semi])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject($f0=[IS NOT NULL($0)])
+         +- LogicalAggregate(group=[{}], m=[MIN($0)])
+            +- LogicalProject(i=[true])
+               +- LogicalFilter(condition=[<($1, 50)])
+                  +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testEXISTS_EquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.a), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[=($3, $0)], joinType=[semi])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testEXISTS_EquiCondition_InnerJoin3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.d), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[=($3, $0)], joinType=[semi])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testEXISTS_NonEquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(>($0, $cor0.a), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[>($3, $0)], joinType=[semi])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testEXISTS_NonEquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), EXISTS({
+LogicalFilter(condition=[AND(<($0, $cor0.d), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[<($3, $0)], joinType=[semi])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_EquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_EquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[AND(=($0, $3), =($1, $4))], joinType=[semi])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0], j=[$1])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_EquiCondition_InnerJoin3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_EquiCondition_InnerJoin4">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(=($cor0.b, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[AND(=($0, $3), =($1, $4))], joinType=[semi])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0], j=[$1])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_EquiCondition_InnerJoin5">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND (x.a, y.e) IN (SELECT z.i, z.j FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, $4, {
+LogicalProject(i=[$0], j=[$1])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(=($0, $6), =($4, $7))], joinType=[semi])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_EquiCondition_InnerJoin6">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(=($0, $6), =($4, $7))], joinType=[semi])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_FullJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+      +- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+         :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+   +- LogicalJoin(condition=[=($3, $6)], joinType=[semi])
+      :- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_FullJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+      +- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+         :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+   +- LogicalJoin(condition=[=($0, $6)], joinType=[semi])
+      :- LogicalJoin(condition=[=($2, $5)], joinType=[full])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_LeftJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+      +- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+         :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+   +- LogicalJoin(condition=[=($3, $6)], joinType=[semi])
+      :- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_LeftJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+      +- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+         :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+   +- LogicalJoin(condition=[=($0, $6)], joinType=[semi])
+      :- LogicalJoin(condition=[=($2, $5)], joinType=[left])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_NonEquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[AND(=($0, $3), >($1, $4))], joinType=[semi])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0], j=[$1])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_NonEquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[AND(=($0, $3), >($1, $4))], joinType=[semi])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0], j=[$1])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_NonEquiCondition_InnerJoin3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(=($0, $6), >($4, $7))], joinType=[semi])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_NonEquiCondition_InnerJoin4">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(=($3, $6), >($1, $7))], joinType=[semi])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_RightJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+      +- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+         :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+   +- LogicalJoin(condition=[=($3, $6)], joinType=[semi])
+      :- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testIN_RightJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(>($4, 100), IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3], e=[$4], f=[$5])
+      +- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+         :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[>($4, 100)])
+   +- LogicalJoin(condition=[=($0, $6)], joinType=[semi])
+      :- LogicalJoin(condition=[=($2, $5)], joinType=[right])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_EXISTS_EquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[<($1, 50)])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[$6], joinType=[anti])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject($f0=[IS NOT NULL($0)])
+         +- LogicalAggregate(group=[{}], m=[MIN($0)])
+            +- LogicalProject(i=[true])
+               +- LogicalFilter(condition=[<($1, 50)])
+                  +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_EXISTS_EquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.a), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[=($3, $0)], joinType=[anti])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_EXISTS_EquiCondition_InnerJoin3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(=($0, $cor0.d), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[=($3, $0)], joinType=[anti])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_EXISTS_NonEquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(>($0, $cor0.a), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[>($3, $0)], joinType=[anti])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_EXISTS_NonEquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND NOT EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(EXISTS({
+LogicalFilter(condition=[AND(<($0, $cor0.d), <($1, 50))])
+  LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[<($3, $0)], joinType=[anti])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_EquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_EquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), =($1, $4))], joinType=[anti])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0], j=[$1])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_EquiCondition_InnerJoin3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_EquiCondition_InnerJoin4">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(=($cor0.b, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), =($1, $4))], joinType=[anti])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0], j=[$1])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_EquiCondition_InnerJoin5">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND (x.a, y.e) NOT IN (SELECT z.i, z.j FROM z WHERE z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, $4, {
+LogicalProject(i=[$0], j=[$1])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(OR(=($0, $6), IS NULL($0), IS NULL($6)), OR(=($4, $7), IS NULL($4), IS NULL($7)))], joinType=[anti])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_EquiCondition_InnerJoin6">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(=($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(OR(=($0, $6), IS NULL($0), IS NULL($6)), =($4, $7))], joinType=[anti])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin1">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), >($1, $4))], joinType=[anti])
+         :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+         +- LogicalProject(i=[$0], j=[$1])
+            +- LogicalFilter(condition=[<($1, 50)])
+               +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin2">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), >($1, $4))], joinType=[anti])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalProject(i=[$0], j=[$1])
+      :     +- LogicalFilter(condition=[<($1, 50)])
+      :        +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND x.a NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($0, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.e, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(OR(=($0, $6), IS NULL($0), IS NULL($6)), >($4, $7))], joinType=[anti])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNOT_IN_NonEquiCondition_InnerJoin4">
+    <Resource name="sql">
+      <![CDATA[SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND y.d NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100), NOT(IN($3, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[AND(>($cor0.b, $1), <($1, 50))])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+})))], variablesSet=[[$cor0]])
+   +- LogicalJoin(condition=[true], joinType=[inner])
+      :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$5])
++- LogicalFilter(condition=[AND(=($2, $5), >($4, 100))])
+   +- LogicalJoin(condition=[AND(OR(=($3, $6), IS NULL($3), IS NULL($6)), >($1, $7))], joinType=[anti])
+      :- LogicalJoin(condition=[true], joinType=[inner])
+      :  :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :  +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0], j=[$1])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.xml
new file mode 100644
index 0000000..b9d53b4
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.xml
@@ -0,0 +1,97 @@
+<?xml version="1.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.
+-->
+<Root>
+  <TestCase name="testCannotTranspose">
+    <Resource name="sql">
+      <![CDATA[
+SELECT a, f FROM
+    (SELECT a * 2 as a, b, d + 1 as d, e, f FROM x, y WHERE x.c = y.f) xy
+WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+      ]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[AND(>($3, 100), IN($2, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[*($0, 2)], b=[$1], d=[+($3, 1)], e=[$4], f=[$5])
+      +- LogicalFilter(condition=[=($2, $5)])
+         +- LogicalJoin(condition=[true], joinType=[inner])
+            :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+            +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[>($3, 100)])
+   +- LogicalJoin(condition=[=($2, $5)], joinType=[semi])
+      :- LogicalProject(a=[*($0, 2)], b=[$1], d=[+($3, 1)], e=[$4], f=[$5])
+      :  +- LogicalFilter(condition=[=($2, $5)])
+      :     +- LogicalJoin(condition=[true], joinType=[inner])
+      :        :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+      :        +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+      +- LogicalProject(i=[$0])
+         +- LogicalFilter(condition=[<($1, 50)])
+            +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTranspose">
+    <Resource name="sql">
+      <![CDATA[
+SELECT a, f FROM
+    (SELECT a, b, d, e, f FROM x, y WHERE x.c = y.f) xy
+WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+      ]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[AND(>($3, 100), IN($2, {
+LogicalProject(i=[$0])
+  LogicalFilter(condition=[<($1, 50)])
+    LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], d=[$3], e=[$4], f=[$5])
+      +- LogicalFilter(condition=[=($2, $5)])
+         +- LogicalJoin(condition=[true], joinType=[inner])
+            :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+            +- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], f=[$4])
++- LogicalFilter(condition=[>($3, 100)])
+   +- LogicalProject(a=[$0], b=[$1], d=[$3], e=[$4], f=[$5])
+      +- LogicalFilter(condition=[=($2, $5)])
+         +- LogicalJoin(condition=[true], joinType=[inner])
+            :- LogicalTableScan(table=[[x, source: [TestTableSource(a, b, c)]]])
+            +- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+               :- LogicalTableScan(table=[[y, source: [TestTableSource(d, e, f)]]])
+               +- LogicalProject(i=[$0])
+                  +- LogicalFilter(condition=[<($1, 50)])
+                     +- LogicalTableScan(table=[[z, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.xml
new file mode 100644
index 0000000..68d6996
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.xml
@@ -0,0 +1,463 @@
+<?xml version="1.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.
+-->
+<Root>
+  <TestCase name="testNotNeedTransposeProject_Anti1">
+    <Resource name="sql">
+      <![CDATA[SELECT * FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+   :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNotNeedTransposeProject_Anti2">
+    <Resource name="sql">
+      <![CDATA[SELECT b + 1, c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalJoin(condition=[OR(=($0, $3), IS NULL($0), IS NULL($3))], joinType=[anti])
+   :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNotNeedTransposeProject_Anti3">
+    <Resource name="sql">
+      <![CDATA[SELECT c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2 WHERE b = e)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(c=[$2])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalFilter(condition=[=($cor0.b, $1)])
+    LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))], variablesSet=[[$cor0]])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(c=[$2])
++- LogicalJoin(condition=[AND(OR(=($0, $3), IS NULL($0), IS NULL($3)), =($1, $4))], joinType=[anti])
+   :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0], e=[$1])
+      +- LogicalFilter(condition=[true])
+         +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNotNeedTransposeProject_Semi1">
+    <Resource name="sql">
+      <![CDATA[SELECT * FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+   :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNotNeedTransposeProject_Semi2">
+    <Resource name="sql">
+      <![CDATA[SELECT b + 1, c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($1, 1)], c=[$2])
++- LogicalJoin(condition=[=($0, $3)], joinType=[semi])
+   :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testNotNeedTransposeProject_Semi3">
+    <Resource name="sql">
+      <![CDATA[SELECT c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2 WHERE b = e)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(c=[$2])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalFilter(condition=[=($cor0.b, $1)])
+    LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})], variablesSet=[[$cor0]])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(c=[$2])
++- LogicalJoin(condition=[AND(=($0, $3), =($1, $4))], joinType=[semi])
+   :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0], e=[$1])
+      +- LogicalFilter(condition=[true])
+         +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Anti1">
+    <Resource name="sql">
+      <![CDATA[SELECT a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalJoin(condition=[OR(=($0, $1), IS NULL($0), IS NULL($1))], joinType=[anti])
+:- LogicalProject(a=[$0])
+:  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+   +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Anti2">
+    <Resource name="sql">
+      <![CDATA[SELECT a + 1 FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalJoin(condition=[OR(=($0, $1), IS NULL($0), IS NULL($1))], joinType=[anti])
+   :- LogicalProject(a=[$0])
+   :  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Anti3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, b FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalJoin(condition=[OR(=($0, $2), IS NULL($0), IS NULL($2))], joinType=[anti])
+:- LogicalProject(a=[$0], b=[$1])
+:  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+   +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Anti4">
+    <Resource name="sql">
+      <![CDATA[SELECT b, a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalJoin(condition=[OR(=($0, $2), IS NULL($0), IS NULL($2))], joinType=[anti])
+   :- LogicalProject(a=[$0], b=[$1])
+   :  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Anti5">
+    <Resource name="sql">
+      <![CDATA[SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t WHERE a NOT IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(d=[$3])
++- LogicalFilter(condition=[NOT(IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+}))])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+      +- LogicalJoin(condition=[true], joinType=[inner])
+         :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(d=[$1])
++- LogicalJoin(condition=[OR(=($0, $2), IS NULL($0), IS NULL($2))], joinType=[anti])
+   :- LogicalProject(a=[$0], d=[$3])
+   :  +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+   :     +- LogicalJoin(condition=[true], joinType=[inner])
+   :        :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   :        +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_EmptyProject">
+    <Resource name="sql">
+      <![CDATA[SELECT * FROM MyTable1 WHERE EXISTS (SELECT * FROM MyTable2, LATERAL TABLE(table_func(f)) AS T(f1) WHERE EXISTS (SELECT * FROM MyTable3))]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalFilter(condition=[EXISTS({
+LogicalFilter(condition=[EXISTS({
+LogicalTableScan(table=[[MyTable3, source: [TestTableSource(i, j, k)]]])
+})])
+  LogicalCorrelate(correlation=[$cor0], joinType=[inner], requiredColumns=[{2}])
+    LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+    LogicalTableFunctionScan(invocation=[table_func($cor0.f)], rowType=[RecordType(VARCHAR(65536) f0)], elementType=[class [Ljava.lang.Object;])
+})])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1], c=[$2])
++- LogicalJoin(condition=[$3], joinType=[semi])
+   :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject($f0=[IS NOT NULL($0)])
+      +- LogicalAggregate(group=[{}], m=[MIN($0)])
+         +- LogicalProject(i=[true])
+            +- LogicalJoin(condition=[$1], joinType=[semi])
+               :- LogicalProject(d=[$0])
+               :  +- LogicalCorrelate(correlation=[$cor0], joinType=[inner], requiredColumns=[{2}])
+               :     :- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+               :     +- LogicalTableFunctionScan(invocation=[table_func($cor0.f)], rowType=[RecordType(VARCHAR(65536) f0)], elementType=[class [Ljava.lang.Object;])
+               +- LogicalProject($f0=[IS NOT NULL($0)])
+                  +- LogicalAggregate(group=[{}], m=[MIN($0)])
+                     +- LogicalProject(i=[true])
+                        +- LogicalTableScan(table=[[MyTable3, source: [TestTableSource(i, j, k)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Semi1">
+    <Resource name="sql">
+      <![CDATA[SELECT a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalJoin(condition=[=($0, $1)], joinType=[semi])
+:- LogicalProject(a=[$0])
+:  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+   +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Semi2">
+    <Resource name="sql">
+      <![CDATA[SELECT a + 1 FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[+($0, 1)])
++- LogicalJoin(condition=[=($0, $1)], joinType=[semi])
+   :- LogicalProject(a=[$0])
+   :  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Semi3">
+    <Resource name="sql">
+      <![CDATA[SELECT a, b FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(a=[$0], b=[$1])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalJoin(condition=[=($0, $2)], joinType=[semi])
+:- LogicalProject(a=[$0], b=[$1])
+:  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
++- LogicalProject(d=[$0])
+   +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Semi4">
+    <Resource name="sql">
+      <![CDATA[SELECT b, a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(b=[$1], a=[$0])
++- LogicalJoin(condition=[=($0, $2)], joinType=[semi])
+   :- LogicalProject(a=[$0], b=[$1])
+   :  +- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testTransposeProject_Semi5">
+    <Resource name="sql">
+      <![CDATA[SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t WHERE a IN (SELECT d FROM MyTable2)]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(d=[$3])
++- LogicalFilter(condition=[IN($0, {
+LogicalProject(d=[$0])
+  LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+})])
+   +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+      +- LogicalJoin(condition=[true], joinType=[inner])
+         :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+         +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(d=[$1])
++- LogicalJoin(condition=[=($0, $2)], joinType=[semi])
+   :- LogicalProject(a=[$0], d=[$3])
+   :  +- LogicalProject(a=[$0], b=[$1], c=[$2], d=[$3])
+   :     +- LogicalJoin(condition=[true], joinType=[inner])
+   :        :- LogicalTableScan(table=[[MyTable1, source: [TestTableSource(a, b, c)]]])
+   :        +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+   +- LogicalProject(d=[$0])
+      +- LogicalTableScan(table=[[MyTable2, source: [TestTableSource(d, e, f)]]])
+]]>
+    </Resource>
+  </TestCase>
+</Root>
diff --git a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml
index 6534b5a..55657c9 100644
--- a/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml
+++ b/flink-table/flink-table-planner-blink/src/test/resources/org/apache/flink/table/plan/stream/sql/join/SemiAntiJoinTest.xml
@@ -150,14 +150,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftSemiJoin], where=[true], select=[a, b, c, $f3])
-   :- Exchange(distribution=[single])
-   :  +- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
-   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[single])
-      +- Calc(select=[])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftSemiJoin], where=[true], select=[a, b, c])
+:- Exchange(distribution=[single])
+:  +- Calc(select=[a, b, c], where=[<(a, 10)])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+   +- Calc(select=[])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -232,9 +231,9 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, c])
    :- Exchange(distribution=[single])
-   :  +- Calc(select=[a, b, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
+   :  +- Calc(select=[a, c], where=[AND(>(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[single])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -264,22 +263,22 @@ LogicalJoin(condition=[=($1, $3)], joinType=[full])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[c])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
-   :- Exchange(distribution=[single])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[single])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- GroupAggregate(select=[MIN(i) AS m])
-            +- Exchange(distribution=[single])
-               +- Calc(select=[true AS i])
-                  +- Join(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
-                     :- Exchange(distribution=[hash[e]])
-                     :  +- Calc(select=[e])
-                     :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                     +- Exchange(distribution=[hash[j]])
-                        +- Calc(select=[j], where=[>(i, 10)])
-                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+Join(joinType=[LeftSemiJoin], where=[$f0], select=[c])
+:- Exchange(distribution=[single])
+:  +- Calc(select=[c])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- GroupAggregate(select=[MIN(i) AS m])
+         +- Exchange(distribution=[single])
+            +- Calc(select=[true AS i])
+               +- Join(joinType=[FullOuterJoin], where=[=(e, j)], select=[e, j])
+                  :- Exchange(distribution=[hash[e]])
+                  :  +- Calc(select=[e])
+                  :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                  +- Exchange(distribution=[hash[j]])
+                     +- Calc(select=[j], where=[>(i, 10)])
+                        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -311,10 +310,11 @@ Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
       +- GroupAggregate(select=[MIN(i) AS m])
          +- Exchange(distribution=[single])
             +- Calc(select=[true AS i])
-               +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f, f0])
+               +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d])
                   :- Exchange(distribution=[single])
-                  :  +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
-                  :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                  :  +- Calc(select=[d])
+                  :     +- Correlate(invocation=[table_func($cor0.f)], correlate=[table(table_func($cor0.f))], select=[d,e,f,f0], rowType=[RecordType(INTEGER d, BIGINT e, VARCHAR(65536) f, VARCHAR(65536) f0)], joinType=[INNER])
+                  :        +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
                   +- Exchange(distribution=[single])
                      +- Calc(select=[IS NOT NULL(m) AS $f0])
                         +- GroupAggregate(select=[MIN(i) AS m])
@@ -400,22 +400,22 @@ LogicalUnion(all=[false])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
-   :- Exchange(distribution=[single])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[single])
-      +- Calc(select=[IS NOT NULL(m) AS $f0])
-         +- GroupAggregate(select=[MIN(i) AS m])
-            +- Exchange(distribution=[single])
-               +- Calc(select=[true AS i])
-                  +- GroupAggregate(groupBy=[e, f], select=[e, f])
-                     +- Exchange(distribution=[hash[e, f]])
-                        +- Union(all=[true], union=[e, f])
-                           :- Calc(select=[e, f], where=[>(d, 10)])
-                           :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-                           +- Calc(select=[j, k], where=[<(i, 100)])
-                              +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+Join(joinType=[LeftSemiJoin], where=[$f0], select=[a])
+:- Exchange(distribution=[single])
+:  +- Calc(select=[a])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+   +- Calc(select=[IS NOT NULL(m) AS $f0])
+      +- GroupAggregate(select=[MIN(i) AS m])
+         +- Exchange(distribution=[single])
+            +- Calc(select=[true AS i])
+               +- GroupAggregate(groupBy=[e, f], select=[e, f])
+                  +- Exchange(distribution=[hash[e, f]])
+                     +- Union(all=[true], union=[e, f])
+                        :- Calc(select=[e, f], where=[>(d, 10)])
+                        :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+                        +- Calc(select=[j, k], where=[<(i, 100)])
+                           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -623,9 +623,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, b, c, $f3, $f4])
++- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, EXPR$0), =($f4, e))], select=[a, c, $f3, $f4])
    :- Exchange(distribution=[hash[$f3, $f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0, e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -681,9 +681,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[a, b, c, $f3])
++- Join(joinType=[LeftSemiJoin], where=[AND(=($f3, d), =(c, f))], select=[b, c, $f3])
    :- Exchange(distribution=[hash[$f3, c]])
-   :  +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+   :  +- Calc(select=[b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
    :     +- Join(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i])
    :        :- Exchange(distribution=[single])
    :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0])
@@ -802,9 +802,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[AND(=(a, d), =(c, k))], select=[a, c])
    :- Exchange(distribution=[hash[a, c]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d, k]])
       +- Calc(select=[d, k])
          +- Join(joinType=[RightOuterJoin], where=[=(d, i)], select=[d, i, k])
@@ -917,14 +918,13 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c, $f3])
-   :- Exchange(distribution=[hash[a]])
-   :  +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[hash[d]])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+:- Exchange(distribution=[hash[a]])
+:  +- Calc(select=[a, b, c], where=[>(b, 10)])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[hash[d]])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -983,11 +983,12 @@ LogicalProject(i=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, b, c, EXPR$0])
++- Join(joinType=[LeftSemiJoin], where=[AND(=(EXPR$0, i), =(k, c))], select=[a, c, EXPR$0])
    :- Exchange(distribution=[hash[EXPR$0, c]])
-   :  +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0])
+   :  +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, c, EXPR$0])
    :     :- Exchange(distribution=[single])
-   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :     :  +- Calc(select=[a, c])
+   :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[single])
    :        +- GroupAggregate(select=[MAX(d) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -1108,9 +1109,10 @@ LogicalProject(EXPR$0=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[=(b, EXPR$0)], select=[a, b])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[EXPR$0]])
       +- Calc(select=[EXPR$0])
          +- GroupAggregate(groupBy=[f], select=[f, MAX(e) AS EXPR$0])
@@ -1222,14 +1224,15 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- Join(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[a, b, c, $f3])
++- Join(joinType=[LeftSemiJoin], where=[=($f3, d)], select=[b, $f3])
    :- Exchange(distribution=[hash[$f3]])
-   :  +- Calc(select=[a, b, c, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
-   :     +- Join(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, c0, i])
+   :  +- Calc(select=[b, CASE(AND(<>(c0, 0), IS NOT NULL(i), IS NOT NULL(a)), 1, 2) AS $f3])
+   :     +- Join(joinType=[LeftOuterJoin], where=[=(a, 1)], select=[a, b, c, i])
    :        :- Exchange(distribution=[single])
-   :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0])
+   :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c])
    :        :     :- Exchange(distribution=[single])
-   :        :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :        :     :  +- Calc(select=[a, b])
+   :        :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :        :     +- Exchange(distribution=[single])
    :        :        +- Calc(select=[c])
    :        :           +- GroupAggregate(select=[COUNT(*) AS c, COUNT(EXPR$0) AS ck])
@@ -1270,11 +1273,12 @@ LogicalProject(j=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, b, c, EXPR$0])
++- Join(joinType=[LeftSemiJoin], where=[=(EXPR$0, j)], select=[a, EXPR$0])
    :- Exchange(distribution=[hash[EXPR$0]])
-   :  +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, b, c, EXPR$0])
+   :  +- Join(joinType=[LeftOuterJoin], where=[true], select=[a, EXPR$0])
    :     :- Exchange(distribution=[single])
-   :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :     :  +- Calc(select=[a])
+   :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :     +- Exchange(distribution=[single])
    :        +- GroupAggregate(select=[MAX(e) AS EXPR$0])
    :           +- Exchange(distribution=[single])
@@ -1313,9 +1317,10 @@ Calc(select=[b])
 +- Join(joinType=[InnerJoin], where=[>(b, $f0)], select=[b, $f0])
    :- Exchange(distribution=[single])
    :  +- Calc(select=[b])
-   :     +- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
+   :     +- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b])
    :        :- Exchange(distribution=[hash[a]])
-   :        :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :        :  +- Calc(select=[a, b])
+   :        :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :        +- Exchange(distribution=[hash[d]])
    :           +- Calc(select=[d], where=[>(e, 10)])
    :              +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
@@ -1349,9 +1354,9 @@ LogicalProject(e=[$1])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[s])
-+- Join(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[b, s, $f2, $f3])
++- Join(joinType=[LeftSemiJoin], where=[=($f3, e)], select=[s, $f3])
    :- Exchange(distribution=[hash[$f3]])
-   :  +- Calc(select=[b, s, $f2, $f3], where=[>($f2, 2)])
+   :  +- Calc(select=[s, $f3], where=[>($f2, 2)])
    :     +- GroupAggregate(groupBy=[b], select=[b, SUM(a) AS s, COUNT(*) AS $f2, MAX(b) AS $f3])
    :        +- Exchange(distribution=[hash[b]])
    :           +- Calc(select=[b, a])
@@ -1386,9 +1391,10 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[c])
-+- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, c])
    :- Exchange(distribution=[hash[a]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, c])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[d]])
       +- Calc(select=[d])
          +- Join(joinType=[FullOuterJoin], where=[=(e, i0)], select=[d, e, i0])
@@ -1594,9 +1600,10 @@ LogicalUnion(all=[false])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[a])
-+- Join(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[=(b, e)], select=[a, b])
    :- Exchange(distribution=[hash[b]])
-   :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :  +- Calc(select=[a, b])
+   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- GroupAggregate(groupBy=[e], select=[e])
          +- Exchange(distribution=[hash[e]])
@@ -1666,16 +1673,16 @@ Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
 :- Exchange(distribution=[hash[a]])
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
-   +- Calc(select=[d])
-      +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d, e, f])
-         :- Exchange(distribution=[single])
-         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-         +- Exchange(distribution=[single])
-            +- Calc(select=[IS NOT NULL(m) AS $f0])
-               +- GroupAggregate(select=[MIN(i) AS m])
-                  +- Exchange(distribution=[single])
-                     +- Calc(select=[true AS i])
-                        +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
+   +- Join(joinType=[LeftSemiJoin], where=[$f0], select=[d])
+      :- Exchange(distribution=[single])
+      :  +- Calc(select=[d])
+      :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+      +- Exchange(distribution=[single])
+         +- Calc(select=[IS NOT NULL(m) AS $f0])
+            +- GroupAggregate(select=[MIN(i) AS m])
+               +- Exchange(distribution=[single])
+                  +- Calc(select=[true AS i])
+                     +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
 ]]>
     </Resource>
   </TestCase>
@@ -1887,9 +1894,10 @@ Join(joinType=[LeftSemiJoin], where=[=(a, d)], select=[a, b, c])
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[hash[d]])
    +- Calc(select=[d])
-      +- Join(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e, f])
+      +- Join(joinType=[LeftSemiJoin], where=[=(e, j)], select=[d, e])
          :- Exchange(distribution=[hash[e]])
-         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+         :  +- Calc(select=[d, e])
+         :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[hash[j]])
             +- Calc(select=[j])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -1917,22 +1925,22 @@ LogicalFilter(condition=[AND(=($cor0.a, $0), <($1, 100))])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Join(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c, d, e, f])
+Join(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
 :- Exchange(distribution=[hash[a]])
-:  +- Join(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c, d, e, f])
-:     :- Exchange(distribution=[hash[b]])
-:     :  +- Join(joinType=[InnerJoin], where=[=(a, d)], select=[a, b, c, d, e, f])
-:     :     :- Exchange(distribution=[hash[a]])
+:  +- Join(joinType=[LeftAntiJoin], where=[=(a, i)], select=[a, b, c])
+:     :- Exchange(distribution=[hash[a]])
+:     :  +- Join(joinType=[LeftAntiJoin], where=[=(b, j)], select=[a, b, c])
+:     :     :- Exchange(distribution=[hash[b]])
 :     :     :  +- Calc(select=[a, b, c], where=[>=(CAST(c), 1:BIGINT)])
 :     :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-:     :     +- Exchange(distribution=[hash[d]])
-:     :        +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
-:     +- Exchange(distribution=[hash[j]])
-:        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
-:           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
-+- Exchange(distribution=[hash[i]])
-   +- Calc(select=[i], where=[<(j, 100)])
-      +- Reused(reference_id=[1])
+:     :     +- Exchange(distribution=[hash[j]])
+:     :        +- Calc(select=[j], where=[>(CAST(k), 50:BIGINT)])
+:     :           +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k], reuse_id=[1])
+:     +- Exchange(distribution=[hash[i]])
+:        +- Calc(select=[i], where=[<(j, 100)])
+:           +- Reused(reference_id=[1])
++- Exchange(distribution=[hash[d]])
+   +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2008,9 +2016,10 @@ Join(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], selec
 :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
 +- Exchange(distribution=[single])
    +- Calc(select=[d])
-      +- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e, f])
+      +- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(e, j), IS NULL(e), IS NULL(j)), =(i, d))], select=[d, e])
          :- Exchange(distribution=[hash[d]])
-         :  +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+         :  +- Calc(select=[d, e])
+         :     +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
          +- Exchange(distribution=[hash[i]])
             +- Calc(select=[j, i])
                +- TableSourceScan(table=[[t, source: [TestTableSource(i, j, k)]]], fields=[i, j, k])
@@ -2058,14 +2067,13 @@ LogicalFilter(condition=[<($cor0.a, 10)])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftAntiJoin], where=[true], select=[a, b, c, $f3])
-   :- Exchange(distribution=[single])
-   :  +- Calc(select=[a, b, c, CAST(IS NOT NULL(a)) AS $f3], where=[<(a, 10)])
-   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[single])
-      +- Calc(select=[])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftAntiJoin], where=[true], select=[a, b, c])
+:- Exchange(distribution=[single])
+:  +- Calc(select=[a, b, c], where=[<(a, 10)])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+   +- Calc(select=[])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2110,9 +2118,9 @@ LogicalTableScan(table=[[r, source: [TestTableSource(d, e, f)]]])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, b, c])
++- Join(joinType=[LeftSemiJoin], where=[$f0], select=[a, c])
    :- Exchange(distribution=[single])
-   :  +- Calc(select=[a, b, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
+   :  +- Calc(select=[a, c], where=[AND(<=(b, 10), NOT(LIKE(c, _UTF-16LE'abc')))])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[single])
       +- Calc(select=[IS NOT NULL(m) AS $f0])
@@ -2230,9 +2238,9 @@ LogicalProject(EXPR$0=[SUBSTRING($2, 1, 5)])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[+(a, 10) AS EXPR$0, c])
-+- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, b, c, $f3, $f4])
++- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, EXPR$0), IS NULL($f3), IS NULL(EXPR$0)), =($f4, e))], select=[a, c, $f3, $f4])
    :- Exchange(distribution=[hash[$f4]])
-   :  +- Calc(select=[a, b, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
+   :  +- Calc(select=[a, c, SUBSTRING(c, 1, 5) AS $f3, +(b, 1) AS $f4])
    :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    +- Exchange(distribution=[hash[e]])
       +- Calc(select=[SUBSTRING(f, 1, 5) AS EXPR$0, e])
@@ -2264,9 +2272,9 @@ LogicalProject(d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[a, b, c, $f3])
++- Join(joinType=[LeftAntiJoin], where=[AND(OR(=($f3, d), IS NULL(d)), =(c, f))], select=[b, c, $f3])
    :- Exchange(distribution=[hash[c]])
-   :  +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+   :  +- Calc(select=[b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
    :     +- Join(joinType=[LeftOuterJoin], where=[=(a, EXPR$0)], select=[a, b, c, c0, ck, i0, c1, ck0, EXPR$0, i])
    :        :- Exchange(distribution=[hash[a]])
    :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0])
@@ -2372,14 +2380,13 @@ LogicalProject(d=[$0])
     </Resource>
     <Resource name="planAfter">
       <![CDATA[
-Calc(select=[a, b, c])
-+- Join(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c, $f3])
-   :- Exchange(distribution=[single])
-   :  +- Calc(select=[a, b, c, CAST(IS NOT NULL(b)) AS $f3], where=[>(b, 10)])
-   :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
-   +- Exchange(distribution=[single])
-      +- Calc(select=[d])
-         +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
+Join(joinType=[LeftAntiJoin], where=[OR(=(a, d), IS NULL(a), IS NULL(d))], select=[a, b, c])
+:- Exchange(distribution=[single])
+:  +- Calc(select=[a, b, c], where=[>(b, 10)])
+:     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
++- Exchange(distribution=[single])
+   +- Calc(select=[d])
+      +- TableSourceScan(table=[[r, source: [TestTableSource(d, e, f)]]], fields=[d, e, f])
 ]]>
     </Resource>
   </TestCase>
@@ -2510,19 +2517,20 @@ LogicalProject(e=[$1], d=[$0])
     <Resource name="planAfter">
       <![CDATA[
 Calc(select=[b])
-+- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[a, b, c, $f3])
++- Join(joinType=[LeftAntiJoin], where=[AND(OR(=(b, e), IS NULL(b), IS NULL(e)), OR(=($f3, d), IS NULL(d)))], select=[b, $f3])
    :- Exchange(distribution=[single])
-   :  +- Calc(select=[a, b, c, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
-   :     +- Join(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c, c0, ck, i0, c1, ck0, j, i])
+   :  +- Calc(select=[b, CASE(OR(=(c0, 0), AND(<>(c0, 0), IS NULL(i0), >=(ck, c0), IS NOT NULL(a))), 1, OR(=(c1, 0), AND(<>(c1, 0), IS NULL(i), >=(ck0, c1), IS NOT NULL(a))), 2, 3) AS $f3])
+   :     +- Join(joinType=[LeftOuterJoin], where=[=(a, j)], select=[a, b, c0, ck, i0, c, ck0, j, i])
    :        :- Exchange(distribution=[hash[a]])
-   :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck, i0, c1, ck0])
+   :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c0, ck, i0, c, ck0])
    :        :     :- Exchange(distribution=[single])
-   :        :     :  +- Calc(select=[a, b, c, c0, ck, i0])
-   :        :     :     +- Join(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, c0, ck, i, i0])
+   :        :     :  +- Calc(select=[a, b, c0, ck, i0])
+   :        :     :     +- Join(joinType=[LeftOuterJoin], where=[=(a, i)], select=[a, b, c, ck, i, i0])
    :        :     :        :- Exchange(distribution=[hash[a]])
-   :        :     :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, c0, ck])
+   :        :     :        :  +- Join(joinType=[InnerJoin], where=[true], select=[a, b, c, ck])
    :        :     :        :     :- Exchange(distribution=[single])
-   :        :     :        :     :  +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
+   :        :     :        :     :  +- Calc(select=[a, b])
+   :        :     :        :     :     +- TableSourceScan(table=[[l, source: [TestTableSource(a, b, c)]]], fields=[a, b, c])
    :        :     :        :     +- Exchange(distribution=[single])
    :        :     :        :        +- GroupAggregate(select=[COUNT(*) AS c, COUNT(i) AS ck])
    :        :     :        :           +- Exchange(distribution=[single])
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.scala
new file mode 100644
index 0000000..74e97d4
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinFilterTransposeRuleTest.scala
@@ -0,0 +1,74 @@
+/*
+ * 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.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+  * Test for [[FlinkSemiAntiJoinFilterTransposeRule]].
+  */
+class FlinkSemiAntiJoinFilterTransposeRuleTest extends TableTestBase {
+
+  private val util = batchTestUtil()
+
+  @Before
+  def setup(): Unit = {
+    util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+    util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+      "rules",
+      FlinkHepRuleSetProgramBuilder.newBuilder
+        .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_SEQUENCE)
+        .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+        .add(RuleSets.ofList(
+          FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+          FlinkSemiAntiJoinFilterTransposeRule.INSTANCE))
+        .build()
+    )
+
+    util.addTableSource[(Int, Long, String)]("MyTable1", 'a, 'b, 'c)
+    util.addTableSource[(Int, Long, String)]("MyTable2", 'd, 'e, 'f)
+  }
+
+  @Test
+  def testSemiJoinFilterTranspose(): Unit = {
+    val sqlQuery =
+      """
+        |SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+        |    WHERE b IN (SELECT e FROM MyTable2)
+      """.stripMargin
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testAntiJoinFilterTranspose(): Unit = {
+    val sqlQuery =
+      """
+        |SELECT * FROM (SELECT * FROM MyTable1 WHERE a > 10) t
+        |    WHERE b NOT IN (SELECT e FROM MyTable2)
+      """.stripMargin
+    util.verifyPlan(sqlQuery)
+  }
+
+}
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.scala
new file mode 100644
index 0000000..67af5d4
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinJoinTransposeRuleTest.scala
@@ -0,0 +1,357 @@
+/*
+ * 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.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+  * Test for [[FlinkSemiAntiJoinJoinTransposeRule]].
+  */
+class FlinkSemiAntiJoinJoinTransposeRuleTest extends TableTestBase {
+
+  private val util = batchTestUtil()
+
+  @Before
+  def setup(): Unit = {
+    util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+    util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+      "rules",
+      FlinkHepRuleSetProgramBuilder.newBuilder
+        .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_COLLECTION)
+        .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+        .add(RuleSets.ofList(
+          FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+          FlinkSemiAntiJoinFilterTransposeRule.INSTANCE,
+          FlinkSemiAntiJoinJoinTransposeRule.INSTANCE))
+        .build()
+    )
+
+    util.addTableSource[(Int, Long, String)]("x", 'a, 'b, 'c)
+    util.addTableSource[(Int, Long, String)]("y", 'd, 'e, 'f)
+    util.addTableSource[(Int, Long, String)]("z", 'i, 'j, 'k)
+  }
+
+  @Test
+  def testIN_EquiCondition_InnerJoin1(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_EquiCondition_InnerJoin2(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_EquiCondition_InnerJoin3(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_EquiCondition_InnerJoin4(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_EquiCondition_InnerJoin5(): Unit = {
+    // keys of semi-join are from both join's right and join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "(x.a, y.e) IN (SELECT z.i, z.j FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_EquiCondition_InnerJoin6(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_NonEquiCondition_InnerJoin1(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_NonEquiCondition_InnerJoin2(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_NonEquiCondition_InnerJoin3(): Unit = {
+    // keys of semi-join are from both join's right and join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_NonEquiCondition_InnerJoin4(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testEXISTS_EquiCondition_InnerJoin1(): Unit = {
+    // no keys
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "EXISTS (SELECT * FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testEXISTS_EquiCondition_InnerJoin2(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testEXISTS_EquiCondition_InnerJoin3(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+
+    // keys of semi-join are from both join's right and join's left
+    // calcite does not support below sql:
+    // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+    //   "EXISTS (SELECT * FROM z WHERE z.i = y.d AND x.b = z.j AND z.j < 50)"
+  }
+
+  @Test
+  def testEXISTS_NonEquiCondition_InnerJoin1(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testEXISTS_NonEquiCondition_InnerJoin2(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+
+    // keys of semi-join are from both join's right and join's left
+    // calcite does not support below sql:
+    // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+    //   "EXISTS (SELECT * FROM z WHERE z.i < y.d AND x.b = z.j AND z.j < 50)"
+  }
+
+  @Test
+  def testNOT_IN_EquiCondition_InnerJoin1(): Unit = {
+    // keys of anti-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d NOT IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+
+  }
+
+  @Test
+  def testNOT_IN_EquiCondition_InnerJoin2(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_EquiCondition_InnerJoin3(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a NOT IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_EquiCondition_InnerJoin4(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a NOT IN (SELECT z.i FROM z WHERE x.b = z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_EquiCondition_InnerJoin5(): Unit = {
+    // keys of semi-join are from both join's right and join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "(x.a, y.e) NOT IN (SELECT z.i, z.j FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_EquiCondition_InnerJoin6(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a NOT IN (SELECT z.i FROM z WHERE y.e = z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_NonEquiCondition_InnerJoin1(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_NonEquiCondition_InnerJoin2(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_NonEquiCondition_InnerJoin3(): Unit = {
+    // keys of semi-join are from both join's right and join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "x.a NOT IN (SELECT z.i FROM z WHERE y.e > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_IN_NonEquiCondition_InnerJoin4(): Unit = {
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "y.d NOT IN (SELECT z.i FROM z WHERE x.b > z.j AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_EXISTS_EquiCondition_InnerJoin1(): Unit = {
+    // no keys
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "NOT EXISTS (SELECT * FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_EXISTS_EquiCondition_InnerJoin2(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "NOT EXISTS (SELECT * FROM z WHERE z.i = x.a AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_EXISTS_EquiCondition_InnerJoin3(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "NOT EXISTS (SELECT * FROM z WHERE z.i = y.d AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+
+    // keys of semi-join are from both join's right and join's left
+    // calcite does not support below sql:
+    // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+    //   "NOT EXISTS (SELECT * FROM z WHERE z.i = y.d AND x.b = z.j AND z.j < 50)"
+  }
+
+  @Test
+  def testNOT_EXISTS_NonEquiCondition_InnerJoin1(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "NOT EXISTS (SELECT * FROM z WHERE z.i > x.a AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testNOT_EXISTS_NonEquiCondition_InnerJoin2(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+      "NOT EXISTS (SELECT * FROM z WHERE z.i < y.d AND z.j < 50)"
+    util.verifyPlan(sqlQuery)
+
+    // keys of semi-join are from both join's right and join's left
+    // calcite does not support below sql:
+    // "SELECT a, f FROM x, y WHERE x.c = y.f AND y.e > 100 AND " +
+    //   "NOT EXISTS (SELECT * FROM z WHERE z.i < y.d AND x.b = z.j AND z.j < 50)"
+  }
+
+  @Test
+  def testIN_LeftJoin1(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy " +
+      "WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_LeftJoin2(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM (SELECT * FROM x LEFT JOIN y ON x.c = y.f) xy " +
+      "WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_RightJoin1(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy " +
+      "WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_RightJoin2(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM (SELECT * FROM x RIGHT JOIN y ON x.c = y.f) xy " +
+      "WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_FullJoin1(): Unit = {
+    // keys of semi-join are from join's right
+    val sqlQuery = "SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy " +
+      "WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testIN_FullJoin2(): Unit = {
+    // keys of semi-join are from join's left
+    val sqlQuery = "SELECT a, f FROM (SELECT * FROM x FULL JOIN y ON x.c = y.f) xy " +
+      "WHERE xy.e > 100 AND xy.a IN (SELECT z.i FROM z WHERE z.j < 50)"
+    util.verifyPlan(sqlQuery)
+  }
+
+}
+
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.scala
new file mode 100644
index 0000000..1b65184
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/FlinkSemiAntiJoinProjectTransposeRuleTest.scala
@@ -0,0 +1,79 @@
+/*
+ * 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.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+  * Test for [[FlinkSemiAntiJoinProjectTransposeRule]].
+  */
+class FlinkSemiAntiJoinProjectTransposeRuleTest extends TableTestBase {
+
+  private val util = batchTestUtil()
+
+  @Before
+  def setup(): Unit = {
+    util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+    util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+      "rules",
+      FlinkHepRuleSetProgramBuilder.newBuilder
+        .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_COLLECTION)
+        .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+        .add(RuleSets.ofList(
+          FlinkSemiAntiJoinProjectTransposeRule.INSTANCE,
+          FlinkSemiAntiJoinFilterTransposeRule.INSTANCE,
+          FlinkSemiAntiJoinJoinTransposeRule.INSTANCE))
+        .build()
+    )
+
+    util.addTableSource[(Int, Long, String)]("x", 'a, 'b, 'c)
+    util.addTableSource[(Int, Long, String)]("y", 'd, 'e, 'f)
+    util.addTableSource[(Int, Long, String)]("z", 'i, 'j, 'k)
+  }
+
+  @Test
+  def testTranspose(): Unit = {
+    val sqlQuery =
+      """
+        |SELECT a, f FROM
+        |    (SELECT a, b, d, e, f FROM x, y WHERE x.c = y.f) xy
+        |WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+      """.stripMargin
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testCannotTranspose(): Unit = {
+    val sqlQuery =
+      """
+        |SELECT a, f FROM
+        |    (SELECT a * 2 as a, b, d + 1 as d, e, f FROM x, y WHERE x.c = y.f) xy
+        |WHERE xy.e > 100 AND xy.d IN (SELECT z.i FROM z WHERE z.j < 50)
+      """.stripMargin
+    util.verifyPlan(sqlQuery)
+  }
+
+}
+
diff --git a/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.scala b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.scala
new file mode 100644
index 0000000..00ae40d
--- /dev/null
+++ b/flink-table/flink-table-planner-blink/src/test/scala/org/apache/flink/table/plan/rules/logical/ProjectSemiAntiJoinTransposeRuleTest.scala
@@ -0,0 +1,149 @@
+/*
+ * 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.flink.table.plan.rules.logical
+
+import org.apache.flink.api.scala._
+import org.apache.flink.table.plan.optimize.program.{FlinkBatchProgram, FlinkHepRuleSetProgramBuilder, HEP_RULES_EXECUTION_TYPE}
+import org.apache.flink.table.runtime.utils.JavaUserDefinedTableFunctions.StringSplit
+import org.apache.flink.table.util.TableTestBase
+
+import org.apache.calcite.plan.hep.HepMatchOrder
+import org.apache.calcite.tools.RuleSets
+import org.junit.{Before, Test}
+
+/**
+  * Test for [[ProjectSemiAntiJoinTransposeRule]].
+  */
+class ProjectSemiAntiJoinTransposeRuleTest extends TableTestBase {
+
+  private val util = batchTestUtil()
+
+  @Before
+  def setup(): Unit = {
+    util.buildBatchProgram(FlinkBatchProgram.DEFAULT_REWRITE)
+    util.tableEnv.getConfig.getCalciteConfig.getBatchProgram.get.addLast(
+      "rules",
+      FlinkHepRuleSetProgramBuilder.newBuilder
+        .setHepRulesExecutionType(HEP_RULES_EXECUTION_TYPE.RULE_SEQUENCE)
+        .setHepMatchOrder(HepMatchOrder.BOTTOM_UP)
+        .add(RuleSets.ofList(ProjectSemiAntiJoinTransposeRule.INSTANCE))
+        .build()
+    )
+
+    util.addTableSource[(Int, Long, String)]("MyTable1", 'a, 'b, 'c)
+    util.addTableSource[(Int, Long, String)]("MyTable2", 'd, 'e, 'f)
+  }
+
+  @Test
+  def testNotNeedTransposeProject_Semi1(): Unit = {
+    util.verifyPlan("SELECT * FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testNotNeedTransposeProject_Semi2(): Unit = {
+    util.verifyPlan("SELECT b + 1, c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testNotNeedTransposeProject_Semi3(): Unit = {
+    util.verifyPlan("SELECT c FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2 WHERE b = e)")
+  }
+
+  @Test
+  def testNotNeedTransposeProject_Anti1(): Unit = {
+    util.verifyPlan("SELECT * FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testNotNeedTransposeProject_Anti2(): Unit = {
+    util.verifyPlan("SELECT b + 1, c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testNotNeedTransposeProject_Anti3(): Unit = {
+    val sqlQuery =
+      "SELECT c FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2 WHERE b = e)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testTransposeProject_Semi1(): Unit = {
+    util.verifyPlan("SELECT a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Semi2(): Unit = {
+    util.verifyPlan("SELECT a + 1 FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Semi3(): Unit = {
+    util.verifyPlan("SELECT a, b FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Semi4(): Unit = {
+    util.verifyPlan("SELECT b, a FROM MyTable1 WHERE a IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Semi5(): Unit = {
+    val sqlQuery = "SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t " +
+      "WHERE a IN (SELECT d FROM MyTable2)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testTransposeProject_Anti1(): Unit = {
+    util.verifyPlan("SELECT a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Anti2(): Unit = {
+    util.verifyPlan( "SELECT a + 1 FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Anti3(): Unit = {
+    util.verifyPlan("SELECT a, b FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Anti4(): Unit = {
+    util.verifyPlan("SELECT b, a FROM MyTable1 WHERE a NOT IN (SELECT d FROM MyTable2)")
+  }
+
+  @Test
+  def testTransposeProject_Anti5(): Unit = {
+    val sqlQuery = "SELECT d FROM (SELECT a, b, c, d FROM MyTable1, MyTable2) t " +
+      "WHERE a NOT IN (SELECT d FROM MyTable2)"
+    util.verifyPlan(sqlQuery)
+  }
+
+  @Test
+  def testTransposeProject_EmptyProject(): Unit = {
+    util.addTableSource[(Int, Long, String)]("MyTable3", 'i, 'j, 'k)
+    util.addFunction("table_func", new StringSplit)
+
+    val sqlQuery = "SELECT * FROM MyTable1 WHERE EXISTS (" +
+      "SELECT * FROM MyTable2, " +
+      "LATERAL TABLE(table_func(f)) AS T(f1) WHERE EXISTS (SELECT * FROM MyTable3))"
+    util.verifyPlan(sqlQuery)
+  }
+}