From eea4e2ed4008ec3005cf8ad7c2f90d5bea62eb7f Mon Sep 17 00:00:00 2001 From: morrySnow Date: Wed, 24 Jul 2024 18:52:30 +0800 Subject: [PATCH] [fix](nerieds) avoid exploration unexpected number of group expressions --- .../apache/doris/nereids/NereidsPlanner.java | 2 +- .../nereids/jobs/cascades/ApplyRuleJob.java | 5 ++ .../org/apache/doris/nereids/memo/Group.java | 12 ++--- .../org/apache/doris/nereids/memo/Memo.java | 7 ++- .../org/apache/doris/nereids/rules/Rule.java | 4 ++ .../apache/doris/nereids/rules/RuleType.java | 47 ++++++++++--------- .../nereids/rules/exploration/CBOUtils.java | 7 +++ .../join/InnerJoinLAsscomProject.java | 2 +- .../join/InnerJoinLeftAssociateProject.java | 2 +- .../join/InnerJoinRightAssociateProject.java | 2 +- .../LogicalJoinSemiJoinTransposeProject.java | 4 +- .../join/OuterJoinAssocProject.java | 2 +- .../join/OuterJoinLAsscomProject.java | 2 +- .../SemiJoinSemiJoinTransposeProject.java | 2 +- .../trees/plans/logical/LogicalProject.java | 9 +++- .../trees/plans/physical/PhysicalProject.java | 13 +++-- .../trees/plans/physical/PhysicalUnion.java | 6 +-- .../shape/query72.out | 14 +++--- .../rf_prune/q21.out | 16 +++---- .../shape/q21.out | 16 +++---- .../tpcds_sf1000/shape/query72.out | 14 +++--- .../tpch_sf1000/rf_prune/q21.out | 16 +++---- .../new_shapes_p0/tpch_sf1000/shape/q21.out | 16 +++---- 23 files changed, 124 insertions(+), 96 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java index 41cfbb659a9ad6..046686255c1489 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java @@ -446,7 +446,7 @@ private PhysicalPlan chooseBestPlan(Group rootGroup, PhysicalProperties physical GroupExpression groupExpression = rootGroup.getLowestCostPlan(physicalProperties).orElseThrow( () -> new AnalysisException("lowestCostPlans with physicalProperties(" + physicalProperties + ") doesn't exist in root group")).second; - if (rootGroup.getEnforcers().contains(groupExpression)) { + if (rootGroup.getEnforcers().containsKey(groupExpression)) { rootGroup.addChosenEnforcerId(groupExpression.getId().asInt()); rootGroup.addChosenEnforcerProperties(physicalProperties); } else { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java index eb4f86bb0cabbb..18b9b86dae798f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java @@ -74,6 +74,11 @@ public final void execute() throws AnalysisException { GroupExpressionMatching groupExpressionMatching = new GroupExpressionMatching(rule.getPattern(), groupExpression); for (Plan plan : groupExpressionMatching) { + if (rule.isExploration() + && context.getCascadesContext().getMemo().getGroupExpressionsSize() > context.getCascadesContext() + .getConnectContext().getSessionVariable().memoMaxGroupExpressionSize) { + break; + } List newPlans = rule.transform(plan, context.getCascadesContext()); for (Plan newPlan : newPlans) { if (newPlan == plan) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java index 2f1e34fae5a012..a01db5546cb761 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java @@ -59,7 +59,7 @@ public class Group { private final List logicalExpressions = Lists.newArrayList(); private final List physicalExpressions = Lists.newArrayList(); - private final List enforcers = Lists.newArrayList(); + private final Map enforcers = Maps.newHashMap(); private boolean isStatsReliable = true; private LogicalProperties logicalProperties; @@ -239,10 +239,10 @@ public GroupExpression getBestPlan(PhysicalProperties properties) { public void addEnforcer(GroupExpression enforcer) { enforcer.setOwnerGroup(this); - enforcers.add(enforcer); + enforcers.put(enforcer, enforcer); } - public List getEnforcers() { + public Map getEnforcers() { return enforcers; } @@ -346,9 +346,9 @@ public void mergeTo(Group target) { parentExpressions.keySet().forEach(parent -> target.addParentExpression(parent)); // move enforcers Ownership - enforcers.forEach(ge -> ge.children().set(0, target)); + enforcers.forEach((k, v) -> k.children().set(0, target)); // TODO: dedup? - enforcers.forEach(enforcer -> target.addEnforcer(enforcer)); + enforcers.forEach((k, v) -> target.addEnforcer(k)); enforcers.clear(); // move LogicalExpression PhysicalExpression Ownership @@ -458,7 +458,7 @@ public String toString() { str.append(" ").append(physicalExpression).append("\n"); } str.append(" enforcers:\n"); - for (GroupExpression enforcer : enforcers) { + for (GroupExpression enforcer : enforcers.keySet()) { str.append(" ").append(enforcer).append("\n"); } if (!chosenEnforcerIdList.isEmpty()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java index 6c530c6aa2fd4a..c34aa00a05379e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java @@ -552,8 +552,7 @@ public void mergeGroup(Group source, Group destination, HashMap pla return; } Group parentOwnerGroup = srcParent.getOwnerGroup(); - HashSet enforcers = new HashSet<>(parentOwnerGroup.getEnforcers()); - if (enforcers.contains(srcParent)) { + if (parentOwnerGroup.getEnforcers().containsKey(srcParent)) { continue; } needReplaceChild.add(srcParent); @@ -946,7 +945,7 @@ private List extractGroupExpressionSatisfyProp(Group group, Phy List exprs = Lists.newArrayList(bestExpr); Set hasVisited = new HashSet<>(); hasVisited.add(bestExpr); - Stream.concat(group.getPhysicalExpressions().stream(), group.getEnforcers().stream()) + Stream.concat(group.getPhysicalExpressions().stream(), group.getEnforcers().keySet().stream()) .forEach(groupExpression -> { if (!groupExpression.getInputPropertiesListOrEmpty(prop).isEmpty() && !groupExpression.equals(bestExpr) && !hasVisited.contains(groupExpression)) { @@ -969,7 +968,7 @@ private List> extractInputProperties(GroupExpression gr res.add(groupExpression.getInputPropertiesList(prop)); // return optimized input for enforcer - if (groupExpression.getOwnerGroup().getEnforcers().contains(groupExpression)) { + if (groupExpression.getOwnerGroup().getEnforcers().containsKey(groupExpression)) { return res; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/Rule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/Rule.java index 207dd6458c9202..7d5b4001d9ae8c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/Rule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/Rule.java @@ -64,6 +64,10 @@ public boolean isRewrite() { return ruleType.getRuleTypeClass() == RuleTypeClass.REWRITE; } + public boolean isExploration() { + return ruleType.getRuleTypeClass() == RuleTypeClass.EXPLORATION; + } + @Override public String toString() { return getRuleType().toString(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index 7525d2a960d222..f2c572f7779e91 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -384,29 +384,29 @@ public enum RuleType { EAGER_SPLIT(RuleTypeClass.EXPLORATION), EXPLORATION_SENTINEL(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_PROJECT_JOIN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_FILTER_JOIN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_PROJECT_FILTER_JOIN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_FILTER_PROJECT_JOIN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_ONLY_JOIN(RuleTypeClass.EXPLORATION), - - MATERIALIZED_VIEW_PROJECT_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_FILTER_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_ONLY_AGGREGATE(RuleTypeClass.EXPLORATION), - - MATERIALIZED_VIEW_PROJECT_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_FILTER_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_ONLY_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.EXPLORATION), - - MATERIALIZED_VIEW_FILTER_SCAN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_PROJECT_SCAN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_FILTER_PROJECT_SCAN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_PROJECT_FILTER_SCAN(RuleTypeClass.EXPLORATION), - MATERIALIZED_VIEW_ONLY_SCAN(RuleTypeClass.EXPLORATION), + MATERIALIZED_VIEW_PROJECT_JOIN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_FILTER_JOIN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_PROJECT_FILTER_JOIN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_FILTER_PROJECT_JOIN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_ONLY_JOIN(RuleTypeClass.MATERIALIZE_VIEW), + + MATERIALIZED_VIEW_PROJECT_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_FILTER_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_ONLY_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + + MATERIALIZED_VIEW_PROJECT_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_FILTER_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_PROJECT_FILTER_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_FILTER_PROJECT_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_ONLY_AGGREGATE_ON_NONE_AGGREGATE(RuleTypeClass.MATERIALIZE_VIEW), + + MATERIALIZED_VIEW_FILTER_SCAN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_PROJECT_SCAN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_FILTER_PROJECT_SCAN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_PROJECT_FILTER_SCAN(RuleTypeClass.MATERIALIZE_VIEW), + MATERIALIZED_VIEW_ONLY_SCAN(RuleTypeClass.MATERIALIZE_VIEW), // implementation rules LOGICAL_ONE_ROW_RELATION_TO_PHYSICAL_ONE_ROW_RELATION(RuleTypeClass.IMPLEMENTATION), @@ -494,6 +494,7 @@ public Rule build( enum RuleTypeClass { REWRITE, EXPLORATION, + MATERIALIZE_VIEW, // This type is used for unit test only. CHECK, IMPLEMENTATION, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/CBOUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/CBOUtils.java index c069dfe0be5037..0ac0c6ea415abb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/CBOUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/CBOUtils.java @@ -42,6 +42,13 @@ public static Set joinChildConditionSlots(LogicalJoin requiredExprIds, Plan plan) { + if (requiredExprIds.equals(plan.getOutputExprIdSet())) { + return plan; + } + return newProject(requiredExprIds, plan); + } + public static Plan newProject(Set requiredExprIds, Plan plan) { List projects = plan.getOutput().stream() .filter(namedExpr -> requiredExprIds.contains(namedExpr.getExprId())) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java index b13451cfe3e771..9ff7f01b829e0a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java @@ -98,7 +98,7 @@ public Rule build() { newTopHashConjuncts.forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); newTopOtherConjuncts.forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); Plan left = CBOUtils.newProject(topUsedExprIds, newBottomJoin); - Plan right = CBOUtils.newProject(topUsedExprIds, b); + Plan right = CBOUtils.newProjectIfNeeded(topUsedExprIds, b); LogicalJoin newTopJoin = bottomJoin.withConjunctsChildren(newTopHashConjuncts, newTopOtherConjuncts, left, right, null); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociateProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociateProject.java index 50666fdaa9df40..e836eac3692f80 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociateProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLeftAssociateProject.java @@ -85,7 +85,7 @@ public Rule build() { newTopHashConjuncts.forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); newTopOtherConjuncts.forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); Plan left = CBOUtils.newProject(topUsedExprIds, newBottomJoin); - Plan right = CBOUtils.newProject(topUsedExprIds, c); + Plan right = CBOUtils.newProjectIfNeeded(topUsedExprIds, c); LogicalJoin newTopJoin = bottomJoin.withConjunctsChildren( newTopHashConjuncts, newTopOtherConjuncts, left, right, null); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociateProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociateProject.java index c2198725f8b3bb..841963e9a7b975 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociateProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinRightAssociateProject.java @@ -81,7 +81,7 @@ public Rule build() { topProject.getProjects().forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); newTopHashConjuncts.forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); newTopOtherConjuncts.forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); - Plan left = CBOUtils.newProject(topUsedExprIds, a); + Plan left = CBOUtils.newProjectIfNeeded(topUsedExprIds, a); Plan right = CBOUtils.newProject(topUsedExprIds, newBottomJoin); LogicalJoin newTopJoin = bottomJoin.withConjunctsChildren( diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/LogicalJoinSemiJoinTransposeProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/LogicalJoinSemiJoinTransposeProject.java index 75d05b7f35dc13..a0e2b83cc1b39a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/LogicalJoinSemiJoinTransposeProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/LogicalJoinSemiJoinTransposeProject.java @@ -70,7 +70,7 @@ public List buildRules() { .forEach(e -> topUsedExprIds.addAll(e.getInputSlotExprIds())); Plan newBottomJoin = topJoin.withChildrenNoContext(a, c, null); Plan left = CBOUtils.newProject(topUsedExprIds, newBottomJoin); - Plan right = CBOUtils.newProject(topUsedExprIds, b); + Plan right = CBOUtils.newProjectIfNeeded(topUsedExprIds, b); Plan newTopJoin = bottomJoin.withChildrenNoContext(left, right, null); return topProject.withChildren(newTopJoin); @@ -102,7 +102,7 @@ public List buildRules() { .forEach(e -> topUsedExprIds.addAll(e.getInputSlotExprIds())); Plan newBottomJoin = topJoin.withChildrenNoContext(a, b, null); Plan left = CBOUtils.newProject(topUsedExprIds, newBottomJoin); - Plan right = CBOUtils.newProject(topUsedExprIds, c); + Plan right = CBOUtils.newProjectIfNeeded(topUsedExprIds, c); Plan newTopJoin = bottomJoin.withChildrenNoContext(left, right, null); return topProject.withChildren(newTopJoin); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinAssocProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinAssocProject.java index 12d2560a364256..af8f002afbd4fd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinAssocProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinAssocProject.java @@ -104,7 +104,7 @@ public Rule build() { topProject.getProjects().forEach(expr -> topUsedExprIds.addAll(expr.getInputSlotExprIds())); bottomJoin.getHashJoinConjuncts().forEach(e -> topUsedExprIds.addAll(e.getInputSlotExprIds())); bottomJoin.getOtherJoinConjuncts().forEach(e -> topUsedExprIds.addAll(e.getInputSlotExprIds())); - Plan left = CBOUtils.newProject(topUsedExprIds, a); + Plan left = CBOUtils.newProjectIfNeeded(topUsedExprIds, a); Plan right = CBOUtils.newProject(topUsedExprIds, newBottomJoin); LogicalJoin newTopJoin = bottomJoin.withChildrenNoContext(left, right, null); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java index 6fe0bb1a4582b7..b8948b22bdea37 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java @@ -90,7 +90,7 @@ public Rule build() { bottomJoin.getHashJoinConjuncts().forEach(e -> topUsedExprIds.addAll(e.getInputSlotExprIds())); bottomJoin.getOtherJoinConjuncts().forEach(e -> topUsedExprIds.addAll(e.getInputSlotExprIds())); Plan left = CBOUtils.newProject(topUsedExprIds, newBottomJoin); - Plan right = CBOUtils.newProject(topUsedExprIds, b); + Plan right = CBOUtils.newProjectIfNeeded(topUsedExprIds, b); LogicalJoin newTopJoin = bottomJoin.withChildrenNoContext(left, right, null); newTopJoin.getJoinReorderContext().copyFrom(topJoin.getJoinReorderContext()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java index 5c61ae2b5261bc..b4a5b177f8c0a9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java @@ -106,7 +106,7 @@ public Rule build() { bottomSemi.getOtherJoinConjuncts().forEach(e -> topUsedExprIds.addAll(e.getInputSlotExprIds())); Plan left = CBOUtils.newProject(topUsedExprIds, newBottomSemi); - Plan right = CBOUtils.newProject(topUsedExprIds, b); + Plan right = CBOUtils.newProjectIfNeeded(topUsedExprIds, b); LogicalJoin newTopSemi = bottomSemi.withChildrenNoContext(left, right, null); newTopSemi.getJoinReorderContext().copyFrom(topSemi.getJoinReorderContext()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java index 44b97086aa0f68..fc07ba876bde37 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java @@ -36,6 +36,8 @@ import org.apache.doris.nereids.util.Utils; import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet; @@ -46,6 +48,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; /** * Logical project plan. @@ -54,6 +57,7 @@ public class LogicalProject extends LogicalUnary projects; + private final Supplier> projectsSet; private final List excepts; private final boolean isDistinct; @@ -83,6 +87,7 @@ private LogicalProject(List projects, List exc this.projects = projects.isEmpty() ? ImmutableList.of(ExpressionUtils.selectMinimumColumn(child.get(0).getOutput())) : projects; + this.projectsSet = Suppliers.memoize(() -> ImmutableSet.copyOf(this.projects)); this.excepts = Utils.fastToImmutableList(excepts); this.isDistinct = isDistinct; } @@ -138,7 +143,7 @@ public boolean equals(Object o) { return false; } LogicalProject that = (LogicalProject) o; - boolean equal = projects.equals(that.projects) + boolean equal = projectsSet.get().equals(that.projectsSet.get()) && excepts.equals(that.excepts) && isDistinct == that.isDistinct; // TODO: should add exprId for UnBoundStar and BoundStar for equality comparison @@ -150,7 +155,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(projects); + return Objects.hash(projectsSet.get()); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java index 02769e47524845..0e7bdf36e8f790 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java @@ -34,12 +34,16 @@ import org.apache.doris.statistics.Statistics; import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; /** * Physical project plan. @@ -47,6 +51,7 @@ public class PhysicalProject extends PhysicalUnary implements Project { private final List projects; + private final Supplier> projectsSet; //multiLayerProjects is used to extract common expressions // projects: (A+B) * 2, (A+B) * 3 // multiLayerProjects: @@ -62,6 +67,7 @@ public PhysicalProject(List projects, Optional LogicalProperties logicalProperties, CHILD_TYPE child) { super(PlanType.PHYSICAL_PROJECT, groupExpression, logicalProperties, child); this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null")); + this.projectsSet = Suppliers.memoize(() -> ImmutableSet.copyOf(this.projects)); } public PhysicalProject(List projects, Optional groupExpression, @@ -70,6 +76,7 @@ public PhysicalProject(List projects, Optional super(PlanType.PHYSICAL_PROJECT, groupExpression, logicalProperties, physicalProperties, statistics, child); this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null")); + this.projectsSet = Suppliers.memoize(() -> ImmutableSet.copyOf(this.projects)); } public List getProjects() { @@ -96,13 +103,13 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - PhysicalProject that = (PhysicalProject) o; - return projects.equals(that.projects); + PhysicalProject that = (PhysicalProject) o; + return projectsSet.get().equals(that.projectsSet.get()); } @Override public int hashCode() { - return Objects.hash(projects); + return Objects.hash(projectsSet.get()); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnion.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnion.java index b3b3eb9e5f702d..ba20c9267059f1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnion.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnion.java @@ -88,7 +88,7 @@ public R accept(PlanVisitor visitor, C context) { @Override public String toString() { - return Utils.toSqlString("PhysicalUnion" + getGroupIdWithPrefix(), + return Utils.toSqlString("PhysicalUnion" + "[" + id.asInt() + "]" + getGroupIdWithPrefix(), "qualifier", qualifier, "outputs", outputs, "regularChildrenOutputs", regularChildrenOutputs, @@ -98,7 +98,7 @@ public String toString() { @Override public PhysicalUnion withChildren(List children) { - return new PhysicalUnion(qualifier, outputs, regularChildrenOutputs, constantExprsList, + return new PhysicalUnion(qualifier, outputs, regularChildrenOutputs, constantExprsList, groupExpression, getLogicalProperties(), children); } @@ -119,7 +119,7 @@ public Plan withGroupExprLogicalPropChildren(Optional groupExpr public PhysicalUnion withPhysicalPropertiesAndStats( PhysicalProperties physicalProperties, Statistics statistics) { return new PhysicalUnion(qualifier, outputs, regularChildrenOutputs, constantExprsList, - Optional.empty(), getLogicalProperties(), physicalProperties, statistics, children); + groupExpression, getLogicalProperties(), physicalProperties, statistics, children); } @Override diff --git a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out index 67ebfbb69dc319..45708bb80f57c4 100644 --- a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out +++ b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out @@ -8,14 +8,12 @@ PhysicalResultSink ----------PhysicalDistribute[DistributionSpecHash] ------------hashAgg[LOCAL] --------------PhysicalProject -----------------hashJoin[INNER_JOIN broadcast] hashCondition=((warehouse.w_warehouse_sk = inventory.inv_warehouse_sk)) otherCondition=() build RFs:RF10 w_warehouse_sk->[inv_warehouse_sk] +----------------hashJoin[LEFT_OUTER_JOIN shuffle] hashCondition=((catalog_returns.cr_item_sk = catalog_sales.cs_item_sk) and (catalog_returns.cr_order_number = catalog_sales.cs_order_number)) otherCondition=() ------------------PhysicalProject ---------------------hashJoin[INNER_JOIN shuffle] hashCondition=((catalog_sales.cs_item_sk = inventory.inv_item_sk) and (inventory.inv_date_sk = d2.d_date_sk)) otherCondition=((inventory.inv_quantity_on_hand < catalog_sales.cs_quantity)) build RFs:RF8 d_date_sk->[inv_date_sk];RF9 cs_item_sk->[inv_item_sk] -----------------------PhysicalOlapScan[inventory] apply RFs: RF8 RF9 RF10 +--------------------hashJoin[INNER_JOIN broadcast] hashCondition=((warehouse.w_warehouse_sk = inventory.inv_warehouse_sk)) otherCondition=() build RFs:RF8 w_warehouse_sk->[inv_warehouse_sk] ----------------------PhysicalProject -------------------------hashJoin[RIGHT_OUTER_JOIN shuffle] hashCondition=((catalog_returns.cr_item_sk = catalog_sales.cs_item_sk) and (catalog_returns.cr_order_number = catalog_sales.cs_order_number)) otherCondition=() build RFs:RF6 cs_item_sk->[cr_item_sk];RF7 cs_order_number->[cr_order_number] ---------------------------PhysicalProject -----------------------------PhysicalOlapScan[catalog_returns] apply RFs: RF6 RF7 +------------------------hashJoin[INNER_JOIN shuffle] hashCondition=((catalog_sales.cs_item_sk = inventory.inv_item_sk) and (inventory.inv_date_sk = d2.d_date_sk)) otherCondition=((inventory.inv_quantity_on_hand < catalog_sales.cs_quantity)) build RFs:RF6 d_date_sk->[inv_date_sk];RF7 cs_item_sk->[inv_item_sk] +--------------------------PhysicalOlapScan[inventory] apply RFs: RF6 RF7 RF8 --------------------------PhysicalProject ----------------------------hashJoin[INNER_JOIN broadcast] hashCondition=((d1.d_week_seq = d2.d_week_seq)) otherCondition=() build RFs:RF5 d_week_seq->[d_week_seq] ------------------------------PhysicalProject @@ -49,6 +47,8 @@ PhysicalResultSink ------------------------------------PhysicalOlapScan[item] ------------------------------PhysicalProject --------------------------------PhysicalOlapScan[date_dim] +----------------------PhysicalProject +------------------------PhysicalOlapScan[warehouse] ------------------PhysicalProject ---------------------PhysicalOlapScan[warehouse] +--------------------PhysicalOlapScan[catalog_returns] diff --git a/regression-test/data/nereids_tpch_shape_sf1000_p0/rf_prune/q21.out b/regression-test/data/nereids_tpch_shape_sf1000_p0/rf_prune/q21.out index 6f08b5e9c35894..0436a7b245b174 100644 --- a/regression-test/data/nereids_tpch_shape_sf1000_p0/rf_prune/q21.out +++ b/regression-test/data/nereids_tpch_shape_sf1000_p0/rf_prune/q21.out @@ -11,15 +11,15 @@ PhysicalResultSink ----------------hashJoin[RIGHT_SEMI_JOIN colocated] hashCondition=((l2.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF4 l_orderkey->[l_orderkey] ------------------PhysicalProject --------------------PhysicalOlapScan[lineitem] apply RFs: RF4 -------------------PhysicalProject ---------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF3 l_orderkey->[o_orderkey] -----------------------PhysicalProject -------------------------filter((orders.o_orderstatus = 'F')) ---------------------------PhysicalOlapScan[orders] apply RFs: RF3 -----------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF2 l_orderkey->[l_orderkey] +------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF3 l_orderkey->[l_orderkey] +--------------------PhysicalProject +----------------------filter((l3.l_receiptdate > l3.l_commitdate)) +------------------------PhysicalOlapScan[lineitem] apply RFs: RF3 +--------------------PhysicalProject +----------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF2 l_orderkey->[o_orderkey] ------------------------PhysicalProject ---------------------------filter((l3.l_receiptdate > l3.l_commitdate)) -----------------------------PhysicalOlapScan[lineitem] apply RFs: RF2 +--------------------------filter((orders.o_orderstatus = 'F')) +----------------------------PhysicalOlapScan[orders] apply RFs: RF2 ------------------------PhysicalProject --------------------------hashJoin[INNER_JOIN broadcast] hashCondition=((supplier.s_suppkey = l1.l_suppkey)) otherCondition=() build RFs:RF1 s_suppkey->[l_suppkey] ----------------------------PhysicalProject diff --git a/regression-test/data/nereids_tpch_shape_sf1000_p0/shape/q21.out b/regression-test/data/nereids_tpch_shape_sf1000_p0/shape/q21.out index 6f08b5e9c35894..0436a7b245b174 100644 --- a/regression-test/data/nereids_tpch_shape_sf1000_p0/shape/q21.out +++ b/regression-test/data/nereids_tpch_shape_sf1000_p0/shape/q21.out @@ -11,15 +11,15 @@ PhysicalResultSink ----------------hashJoin[RIGHT_SEMI_JOIN colocated] hashCondition=((l2.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF4 l_orderkey->[l_orderkey] ------------------PhysicalProject --------------------PhysicalOlapScan[lineitem] apply RFs: RF4 -------------------PhysicalProject ---------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF3 l_orderkey->[o_orderkey] -----------------------PhysicalProject -------------------------filter((orders.o_orderstatus = 'F')) ---------------------------PhysicalOlapScan[orders] apply RFs: RF3 -----------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF2 l_orderkey->[l_orderkey] +------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF3 l_orderkey->[l_orderkey] +--------------------PhysicalProject +----------------------filter((l3.l_receiptdate > l3.l_commitdate)) +------------------------PhysicalOlapScan[lineitem] apply RFs: RF3 +--------------------PhysicalProject +----------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF2 l_orderkey->[o_orderkey] ------------------------PhysicalProject ---------------------------filter((l3.l_receiptdate > l3.l_commitdate)) -----------------------------PhysicalOlapScan[lineitem] apply RFs: RF2 +--------------------------filter((orders.o_orderstatus = 'F')) +----------------------------PhysicalOlapScan[orders] apply RFs: RF2 ------------------------PhysicalProject --------------------------hashJoin[INNER_JOIN broadcast] hashCondition=((supplier.s_suppkey = l1.l_suppkey)) otherCondition=() build RFs:RF1 s_suppkey->[l_suppkey] ----------------------------PhysicalProject diff --git a/regression-test/data/new_shapes_p0/tpcds_sf1000/shape/query72.out b/regression-test/data/new_shapes_p0/tpcds_sf1000/shape/query72.out index 9ff0cd2f442fed..b9d2d9210df92e 100644 --- a/regression-test/data/new_shapes_p0/tpcds_sf1000/shape/query72.out +++ b/regression-test/data/new_shapes_p0/tpcds_sf1000/shape/query72.out @@ -8,14 +8,12 @@ PhysicalResultSink ----------PhysicalDistribute[DistributionSpecHash] ------------hashAgg[LOCAL] --------------PhysicalProject -----------------hashJoin[INNER_JOIN broadcast] hashCondition=((warehouse.w_warehouse_sk = inventory.inv_warehouse_sk)) otherCondition=() build RFs:RF10 w_warehouse_sk->[inv_warehouse_sk] +----------------hashJoin[LEFT_OUTER_JOIN bucketShuffle] hashCondition=((catalog_returns.cr_item_sk = catalog_sales.cs_item_sk) and (catalog_returns.cr_order_number = catalog_sales.cs_order_number)) otherCondition=() ------------------PhysicalProject ---------------------hashJoin[INNER_JOIN shuffle] hashCondition=((catalog_sales.cs_item_sk = inventory.inv_item_sk) and (inventory.inv_date_sk = d2.d_date_sk)) otherCondition=((inventory.inv_quantity_on_hand < catalog_sales.cs_quantity)) build RFs:RF8 d_date_sk->[inv_date_sk];RF9 cs_item_sk->[inv_item_sk] -----------------------PhysicalOlapScan[inventory] apply RFs: RF8 RF9 RF10 +--------------------hashJoin[INNER_JOIN broadcast] hashCondition=((warehouse.w_warehouse_sk = inventory.inv_warehouse_sk)) otherCondition=() build RFs:RF8 w_warehouse_sk->[inv_warehouse_sk] ----------------------PhysicalProject -------------------------hashJoin[RIGHT_OUTER_JOIN bucketShuffle] hashCondition=((catalog_returns.cr_item_sk = catalog_sales.cs_item_sk) and (catalog_returns.cr_order_number = catalog_sales.cs_order_number)) otherCondition=() build RFs:RF6 cs_item_sk->[cr_item_sk];RF7 cs_order_number->[cr_order_number] ---------------------------PhysicalProject -----------------------------PhysicalOlapScan[catalog_returns] apply RFs: RF6 RF7 +------------------------hashJoin[INNER_JOIN shuffleBucket] hashCondition=((catalog_sales.cs_item_sk = inventory.inv_item_sk) and (inventory.inv_date_sk = d2.d_date_sk)) otherCondition=((inventory.inv_quantity_on_hand < catalog_sales.cs_quantity)) build RFs:RF6 d_date_sk->[inv_date_sk];RF7 cs_item_sk->[inv_item_sk] +--------------------------PhysicalOlapScan[inventory] apply RFs: RF6 RF7 RF8 --------------------------PhysicalProject ----------------------------hashJoin[INNER_JOIN broadcast] hashCondition=((d1.d_week_seq = d2.d_week_seq)) otherCondition=() build RFs:RF5 d_week_seq->[d_week_seq] ------------------------------PhysicalProject @@ -49,6 +47,8 @@ PhysicalResultSink ------------------------------------PhysicalOlapScan[item] ------------------------------PhysicalProject --------------------------------PhysicalOlapScan[date_dim] +----------------------PhysicalProject +------------------------PhysicalOlapScan[warehouse] ------------------PhysicalProject ---------------------PhysicalOlapScan[warehouse] +--------------------PhysicalOlapScan[catalog_returns] diff --git a/regression-test/data/new_shapes_p0/tpch_sf1000/rf_prune/q21.out b/regression-test/data/new_shapes_p0/tpch_sf1000/rf_prune/q21.out index 6f08b5e9c35894..0436a7b245b174 100644 --- a/regression-test/data/new_shapes_p0/tpch_sf1000/rf_prune/q21.out +++ b/regression-test/data/new_shapes_p0/tpch_sf1000/rf_prune/q21.out @@ -11,15 +11,15 @@ PhysicalResultSink ----------------hashJoin[RIGHT_SEMI_JOIN colocated] hashCondition=((l2.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF4 l_orderkey->[l_orderkey] ------------------PhysicalProject --------------------PhysicalOlapScan[lineitem] apply RFs: RF4 -------------------PhysicalProject ---------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF3 l_orderkey->[o_orderkey] -----------------------PhysicalProject -------------------------filter((orders.o_orderstatus = 'F')) ---------------------------PhysicalOlapScan[orders] apply RFs: RF3 -----------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF2 l_orderkey->[l_orderkey] +------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF3 l_orderkey->[l_orderkey] +--------------------PhysicalProject +----------------------filter((l3.l_receiptdate > l3.l_commitdate)) +------------------------PhysicalOlapScan[lineitem] apply RFs: RF3 +--------------------PhysicalProject +----------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF2 l_orderkey->[o_orderkey] ------------------------PhysicalProject ---------------------------filter((l3.l_receiptdate > l3.l_commitdate)) -----------------------------PhysicalOlapScan[lineitem] apply RFs: RF2 +--------------------------filter((orders.o_orderstatus = 'F')) +----------------------------PhysicalOlapScan[orders] apply RFs: RF2 ------------------------PhysicalProject --------------------------hashJoin[INNER_JOIN broadcast] hashCondition=((supplier.s_suppkey = l1.l_suppkey)) otherCondition=() build RFs:RF1 s_suppkey->[l_suppkey] ----------------------------PhysicalProject diff --git a/regression-test/data/new_shapes_p0/tpch_sf1000/shape/q21.out b/regression-test/data/new_shapes_p0/tpch_sf1000/shape/q21.out index 6f08b5e9c35894..0436a7b245b174 100644 --- a/regression-test/data/new_shapes_p0/tpch_sf1000/shape/q21.out +++ b/regression-test/data/new_shapes_p0/tpch_sf1000/shape/q21.out @@ -11,15 +11,15 @@ PhysicalResultSink ----------------hashJoin[RIGHT_SEMI_JOIN colocated] hashCondition=((l2.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF4 l_orderkey->[l_orderkey] ------------------PhysicalProject --------------------PhysicalOlapScan[lineitem] apply RFs: RF4 -------------------PhysicalProject ---------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF3 l_orderkey->[o_orderkey] -----------------------PhysicalProject -------------------------filter((orders.o_orderstatus = 'F')) ---------------------------PhysicalOlapScan[orders] apply RFs: RF3 -----------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF2 l_orderkey->[l_orderkey] +------------------hashJoin[RIGHT_ANTI_JOIN colocated] hashCondition=((l3.l_orderkey = l1.l_orderkey)) otherCondition=(( not (l_suppkey = l_suppkey))) build RFs:RF3 l_orderkey->[l_orderkey] +--------------------PhysicalProject +----------------------filter((l3.l_receiptdate > l3.l_commitdate)) +------------------------PhysicalOlapScan[lineitem] apply RFs: RF3 +--------------------PhysicalProject +----------------------hashJoin[INNER_JOIN colocated] hashCondition=((orders.o_orderkey = l1.l_orderkey)) otherCondition=() build RFs:RF2 l_orderkey->[o_orderkey] ------------------------PhysicalProject ---------------------------filter((l3.l_receiptdate > l3.l_commitdate)) -----------------------------PhysicalOlapScan[lineitem] apply RFs: RF2 +--------------------------filter((orders.o_orderstatus = 'F')) +----------------------------PhysicalOlapScan[orders] apply RFs: RF2 ------------------------PhysicalProject --------------------------hashJoin[INNER_JOIN broadcast] hashCondition=((supplier.s_suppkey = l1.l_suppkey)) otherCondition=() build RFs:RF1 s_suppkey->[l_suppkey] ----------------------------PhysicalProject