This is an automated email from the ASF dual-hosted git repository. jakevin pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 2794427e7f3 [enhancement](Nereids): refactor eliminating inner join by foreign key (#28816) 2794427e7f3 is described below commit 2794427e7f3a020e1131a433739c3e638bd61381 Author: 谢健 <jianx...@gmail.com> AuthorDate: Fri Dec 29 13:41:54 2023 +0800 [enhancement](Nereids): refactor eliminating inner join by foreign key (#28816) --- .../nereids/rules/rewrite/EliminateJoinByFK.java | 246 ++++++++++----------- .../nereids/util/ImmutableEquivalenceSet.java | 20 +- .../rules/rewrite/EliminateJoinByFkTest.java | 102 +++++++-- .../shape/query23.out | 41 ++-- .../noStatsRfPrune/query23.out | 48 ++-- .../no_stats_shape/query23.out | 48 ++-- .../rf_prune/query23.out | 41 ++-- .../nereids_tpcds_shape_sf100_p0/shape/query23.out | 41 ++-- 8 files changed, 300 insertions(+), 287 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFK.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFK.java index 17fcf7842ef..594dee50853 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFK.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFK.java @@ -29,24 +29,17 @@ import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait; import org.apache.doris.nereids.trees.plans.Plan; -import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; -import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalRelation; -import org.apache.doris.nereids.trees.plans.logical.LogicalSort; -import org.apache.doris.nereids.trees.plans.logical.LogicalTopN; -import org.apache.doris.nereids.trees.plans.logical.LogicalWindow; import org.apache.doris.nereids.trees.plans.visitor.CustomRewriter; import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter; import org.apache.doris.nereids.util.ImmutableEquivalenceSet; -import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; @@ -54,7 +47,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nullable; @@ -80,7 +72,9 @@ public class EliminateJoinByFK extends DefaultPlanRewriter<JobContext> implement @Override public Plan visit(Plan plan, ForeignKeyContext context) { Plan newPlan = visitChildren(this, plan, context); - context.passThroughPlan(plan); + // always expire primary key except filter, project and join. + // always keep foreign key alive + context.expirePrimaryKey(plan); return newPlan; } @@ -97,35 +91,29 @@ public class EliminateJoinByFK extends DefaultPlanRewriter<JobContext> implement return relation; } - private boolean canEliminate(LogicalJoin<?, ?> join, BiMap<Slot, Slot> equalSlots, ForeignKeyContext context) { + private boolean canEliminate(LogicalJoin<?, ?> join, Map<Slot, Slot> primaryToForeign, + ForeignKeyContext context) { if (!join.getOtherJoinConjuncts().isEmpty()) { return false; } if (!join.getJoinType().isInnerJoin() && !join.getJoinType().isSemiJoin()) { return false; } - return context.satisfyConstraint(equalSlots, join); + return context.satisfyConstraint(primaryToForeign, join); } - private boolean isForeignKeyAndUnique(Plan plan, - Set<Slot> keySet, ForeignKeyContext context) { - boolean unique = keySet.stream() - .allMatch(s -> plan.getLogicalProperties().getFunctionalDependencies().isUnique(s)); - return unique && context.isForeignKey(keySet); - } - - private @Nullable Map<Expression, Expression> tryGetOutputToChildMap(Plan child, - Set<Slot> output, BiMap<Slot, Slot> equalSlots) { - Set<Slot> residual = Sets.difference(output, child.getOutputSet()); - if (equalSlots.keySet().containsAll(residual)) { - return residual.stream() - .collect(ImmutableMap.toImmutableMap(e -> e, equalSlots::get)); - } - if (equalSlots.values().containsAll(residual)) { - return residual.stream() - .collect(ImmutableMap.toImmutableMap(e -> e, e -> equalSlots.inverse().get(e))); + private @Nullable Map<Expression, Expression> tryMapOutputToForeignPlan(Plan foreignPlan, + Set<Slot> output, Map<Slot, Slot> primaryToForeign) { + Set<Slot> residualPrimary = Sets.difference(output, foreignPlan.getOutputSet()); + ImmutableMap.Builder<Expression, Expression> builder = new ImmutableMap.Builder<>(); + for (Slot slot : residualPrimary) { + if (primaryToForeign.containsKey(slot)) { + builder.put(slot, primaryToForeign.get(slot)); + } else { + return null; + } } - return null; + return builder.build(); } private Plan applyNullCompensationFilter(Plan child, Set<Slot> childSlots) { @@ -139,47 +127,56 @@ public class EliminateJoinByFK extends DefaultPlanRewriter<JobContext> implement return new LogicalFilter<>(predicates, child); } - private @Nullable Plan tryConstructPlanWithJoinChild(LogicalProject<LogicalJoin<?, ?>> project, Plan child, - BiMap<Slot, Slot> equalSlots, ForeignKeyContext context) { + private Plan tryEliminatePrimaryPlan(LogicalProject<LogicalJoin<?, ?>> project, + Plan foreignPlan, Set<Slot> foreignKeys, + Map<Slot, Slot> primaryToForeign, ForeignKeyContext context) { Set<Slot> output = project.getInputSlots(); - Set<Slot> keySet = child.getOutputSet().containsAll(equalSlots.keySet()) - ? equalSlots.keySet() - : equalSlots.values(); - Map<Expression, Expression> outputToRight = tryGetOutputToChildMap(child, output, equalSlots); - if (outputToRight != null && isForeignKeyAndUnique(child, keySet, context)) { + Map<Expression, Expression> outputToForeign = + tryMapOutputToForeignPlan(foreignPlan, output, primaryToForeign); + if (outputToForeign != null && canEliminate(project.child(), primaryToForeign, context)) { List<NamedExpression> newProjects = project.getProjects().stream() - .map(e -> outputToRight.containsKey(e) - ? new Alias(e.getExprId(), outputToRight.get(e), e.toSql()) - : (NamedExpression) e.rewriteUp(s -> outputToRight.getOrDefault(s, s))) + .map(e -> outputToForeign.containsKey(e) + ? new Alias(e.getExprId(), outputToForeign.get(e), e.toSql()) + : (NamedExpression) e.rewriteUp(s -> outputToForeign.getOrDefault(s, s))) .collect(ImmutableList.toImmutableList()); return project.withProjects(newProjects) - .withChildren(applyNullCompensationFilter(child, keySet)); + .withChildren(applyNullCompensationFilter(foreignPlan, foreignKeys)); + } + return project; + } + + private @Nullable Map<Slot, Slot> mapPrimaryToForeign(ImmutableEquivalenceSet<Slot> equivalenceSet, + Set<Slot> foreignKeys) { + ImmutableMap.Builder<Slot, Slot> builder = new ImmutableMap.Builder<>(); + for (Slot foreignSlot : foreignKeys) { + Set<Slot> primarySlots = equivalenceSet.calEqualSet(foreignSlot); + if (primarySlots.size() != 1) { + return null; + } + builder.put(primarySlots.iterator().next(), foreignSlot); } - return null; + return builder.build(); } // Right now we only support eliminate inner join, which should meet the following condition: // 1. only contain null-reject equal condition, and which all meet fk-pk constraint // 2. only output foreign table output or can be converted to foreign table output - // 3. foreign key is unique // 4. if foreign key is null, add a isNotNull predicate for null-reject join condition private Plan eliminateJoin(LogicalProject<LogicalJoin<?, ?>> project, ForeignKeyContext context) { LogicalJoin<?, ?> join = project.child(); ImmutableEquivalenceSet<Slot> equalSet = join.getEqualSlots(); - BiMap<Slot, Slot> equalSlots = equalSet.tryToMap(); - if (equalSlots == null) { - return project; - } - if (!canEliminate(join, equalSlots, context)) { - return project; - } - Plan keepLeft = tryConstructPlanWithJoinChild(project, join.left(), equalSlots, context); - if (keepLeft != null) { - return keepLeft; - } - Plan keepRight = tryConstructPlanWithJoinChild(project, join.right(), equalSlots, context); - if (keepRight != null) { - return keepRight; + Set<Slot> leftSlots = Sets.intersection(join.left().getOutputSet(), equalSet.getAllItemSet()); + Set<Slot> rightSlots = Sets.intersection(join.right().getOutputSet(), equalSet.getAllItemSet()); + if (context.isForeignKey(leftSlots) && context.isPrimaryKey(rightSlots)) { + Map<Slot, Slot> primaryToForeignSlot = mapPrimaryToForeign(equalSet, leftSlots); + if (primaryToForeignSlot != null) { + return tryEliminatePrimaryPlan(project, join.left(), leftSlots, primaryToForeignSlot, context); + } + } else if (context.isForeignKey(rightSlots) && context.isPrimaryKey(leftSlots)) { + Map<Slot, Slot> primaryToForeignSlot = mapPrimaryToForeign(equalSet, rightSlots); + if (primaryToForeignSlot != null) { + return tryEliminatePrimaryPlan(project, join.right(), rightSlots, primaryToForeignSlot, context); + } } return project; } @@ -197,32 +194,29 @@ public class EliminateJoinByFK extends DefaultPlanRewriter<JobContext> implement } return project; } + + @Override + public Plan visitLogicalJoin(LogicalJoin<?, ?> join, ForeignKeyContext context) { + Plan plan = visitChildren(this, join, context); + context.addJoin(join); + return plan; + } + + @Override + public Plan visitLogicalFilter(LogicalFilter<?> filter, ForeignKeyContext context) { + Plan plan = visitChildren(this, filter, context); + context.addFilter(filter); + return plan; + } } private static class ForeignKeyContext { - static Set<Class<?>> propagatePrimaryKeyOperator = ImmutableSet - .<Class<?>>builder() - .add(LogicalProject.class) - .add(LogicalSort.class) - .add(LogicalJoin.class) - .build(); - static Set<Class<?>> propagateForeignKeyOperator = ImmutableSet - .<Class<?>>builder() - .add(LogicalProject.class) - .add(LogicalSort.class) - .add(LogicalJoin.class) - .add(LogicalFilter.class) - .add(LogicalTopN.class) - .add(LogicalLimit.class) - .add(LogicalAggregate.class) - .add(LogicalWindow.class) - .build(); Set<Map<Column, Column>> constraints = new HashSet<>(); Set<Column> foreignKeys = new HashSet<>(); Set<Column> primaryKeys = new HashSet<>(); Map<Slot, Column> slotToColumn = new HashMap<>(); - Map<Column, Set<LogicalJoin<?, ?>>> columnWithJoin = new HashMap<>(); - Map<Column, Set<Expression>> columnWithPredicates = new HashMap<>(); + Map<Slot, Set<LogicalJoin<?, ?>>> slotWithJoin = new HashMap<>(); + Map<Slot, Set<Expression>> slotWithPredicates = new HashMap<>(); public void putAllForeignKeys(TableIf table) { table.getForeignKeyConstraints().forEach(c -> { @@ -238,6 +232,11 @@ public class EliminateJoinByFK extends DefaultPlanRewriter<JobContext> implement key.stream().map(s -> slotToColumn.get(s)).collect(Collectors.toSet())); } + public boolean isPrimaryKey(Set<Slot> key) { + return primaryKeys.containsAll( + key.stream().map(s -> slotToColumn.get(s)).collect(Collectors.toSet())); + } + public void putSlot(SlotReference slot) { if (!slot.getColumn().isPresent()) { return; @@ -252,81 +251,62 @@ public class EliminateJoinByFK extends DefaultPlanRewriter<JobContext> implement } } - public void passThroughPlan(Plan plan) { - Set<Column> output = plan.getOutput().stream() + public void addFilter(LogicalFilter<?> filter) { + filter.getOutput().stream() + .filter(slotToColumn::containsKey) + .forEach(slot -> { + slotWithPredicates.computeIfAbsent(slot, v -> new HashSet<>()); + slotWithPredicates.get(slot).addAll(filter.getConjuncts()); + }); + } + + public void addJoin(LogicalJoin<?, ?> join) { + join.getOutput().stream() + .filter(slotToColumn::containsKey) + .forEach(slot -> + slotWithJoin.computeIfAbsent(slot, v -> Sets.newHashSet((join)))); + } + + public void expirePrimaryKey(Plan plan) { + plan.getOutput().stream() .filter(slotToColumn::containsKey) .map(s -> slotToColumn.get(s)) - .collect(ImmutableSet.toImmutableSet()); - if (plan instanceof LogicalJoin) { - output.forEach(c -> - columnWithJoin.computeIfAbsent(c, v -> Sets.newHashSet((LogicalJoin<?, ?>) plan))); - return; - } - if (plan instanceof LogicalFilter) { - output.forEach(c -> { - columnWithPredicates.computeIfAbsent(c, v -> new HashSet<>()); - columnWithPredicates.get(c).addAll(((LogicalFilter<?>) plan).getConjuncts()); - }); - return; - } - if (!propagatePrimaryKeyOperator.contains(plan.getClass())) { - output.forEach(primaryKeys::remove); - } - if (!propagateForeignKeyOperator.contains(plan.getClass())) { - output.forEach(foreignKeys::remove); - } + .forEach(primaryKeys::remove); } - public boolean satisfyConstraint(BiMap<Slot, Slot> equalSlots, LogicalJoin<?, ?> join) { - ImmutableMap.Builder<Column, Column> foreignToPrimaryBuilder = new Builder<>(); - for (Entry<Slot, Slot> entry : equalSlots.entrySet()) { - Slot left = entry.getKey(); - Slot right = entry.getValue(); - if (!slotToColumn.containsKey(left) || !slotToColumn.containsKey(right)) { - return false; - } - Column leftColumn = slotToColumn.get(left); - Column rightColumn = slotToColumn.get(right); - if (foreignKeys.contains(leftColumn)) { - foreignToPrimaryBuilder.put(leftColumn, rightColumn); - } else if (foreignKeys.contains(rightColumn)) { - foreignToPrimaryBuilder.put(rightColumn, leftColumn); - } else { - return false; - } - } - Map<Column, Column> foreignToPrimary = foreignToPrimaryBuilder.build(); + public boolean satisfyConstraint(Map<Slot, Slot> primaryToForeign, LogicalJoin<?, ?> join) { + Map<Column, Column> foreignToPrimary = primaryToForeign.entrySet().stream() + .collect(ImmutableMap.toImmutableMap( + e -> slotToColumn.get(e.getValue()), + e -> slotToColumn.get(e.getKey()))); // The primary key can only contain join that may be eliminated - if (!foreignToPrimary.values().stream().allMatch(p -> - columnWithJoin.get(p).size() == 1 && columnWithJoin.get(p).iterator().next() == join)) { + if (!primaryToForeign.keySet().stream().allMatch(p -> + slotWithJoin.get(p).size() == 1 && slotWithJoin.get(p).iterator().next() == join)) { return false; } // The foreign key's filters must contain primary filters - if (!isPredicateCompatible(equalSlots, foreignToPrimary)) { + if (!isPredicateCompatible(primaryToForeign)) { return false; } return constraints.contains(foreignToPrimary); } - private boolean isPredicateCompatible(BiMap<Slot, Slot> equalSlots, Map<Column, Column> foreignToPrimary) { - return foreignToPrimary.entrySet().stream().allMatch(fp -> { - BiMap<Slot, Slot> primarySlotToForeign = equalSlots.keySet().stream() - .map(slotToColumn::get) - .anyMatch(primaryKeys::contains) - ? equalSlots : - equalSlots.inverse(); - if (!columnWithPredicates.containsKey(fp.getValue())) { + // When predicates of foreign keys is a subset of that of primary keys + private boolean isPredicateCompatible(Map<Slot, Slot> primaryToForeign) { + return primaryToForeign.entrySet().stream().allMatch(pf -> { + // There is no predicate in primary key + if (!slotWithPredicates.containsKey(pf.getKey()) || slotWithPredicates.get(pf.getKey()).isEmpty()) { return true; } - Set<Expression> primaryPredicates = columnWithPredicates.get(fp.getValue()).stream() - .map(e -> e.rewriteUp( - s -> s instanceof Slot ? primarySlotToForeign.getOrDefault(s, (Slot) s) : s)) - .collect(Collectors.toSet()); - if (columnWithPredicates.get(fp.getKey()) == null && !columnWithPredicates.isEmpty()) { + // There are some predicates in primary key but there is no predicate in foreign key + if (slotWithPredicates.containsKey(pf.getValue()) && slotWithPredicates.get(pf.getValue()).isEmpty()) { return false; - } else { - return columnWithPredicates.get(fp.getKey()).containsAll(primaryPredicates); } + Set<Expression> primaryPredicates = slotWithPredicates.get(pf.getKey()).stream() + .map(e -> e.rewriteUp( + s -> s instanceof Slot ? primaryToForeign.getOrDefault(s, (Slot) s) : s)) + .collect(Collectors.toSet()); + return slotWithPredicates.get(pf.getValue()).containsAll(primaryPredicates); }); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEquivalenceSet.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEquivalenceSet.java index e54ecb7c9e7..66d20597fc1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEquivalenceSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ImmutableEquivalenceSet.java @@ -17,15 +17,12 @@ package org.apache.doris.nereids.util; -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import java.util.HashMap; import java.util.Map; import java.util.Set; -import javax.annotation.Nullable; /** * EquivalenceSet @@ -77,25 +74,16 @@ public class ImmutableEquivalenceSet<T> { } /** - * cal equal set for a + * cal equal set for a except self */ public Set<T> calEqualSet(T a) { T ra = root.get(a); return root.keySet().stream() - .filter(t -> root.get(t).equals(ra)) + .filter(t -> root.get(t).equals(ra) && !t.equals(a)) .collect(ImmutableSet.toImmutableSet()); } - /** - * try to convert it to a map, such as a = b c = d. - * When meets a = b a = c, return null - */ - public @Nullable BiMap<T, T> tryToMap() { - if (root.values().stream().distinct().count() * 2 != root.size()) { - return null; - } - return root.keySet().stream() - .filter(t -> !root.get(t).equals(t)) - .collect(ImmutableBiMap.toImmutableBiMap(t -> t, root::get)); + public Set<T> getAllItemSet() { + return ImmutableSet.copyOf(root.keySet()); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java index 721e94b144d..921e4541251 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/EliminateJoinByFkTest.java @@ -21,6 +21,7 @@ import org.apache.doris.nereids.util.MemoPatternMatchSupported; import org.apache.doris.nereids.util.PlanChecker; import org.apache.doris.utframe.TestWithFeService; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; class EliminateJoinByFkTest extends TestWithFeService implements MemoPatternMatchSupported { @@ -56,59 +57,102 @@ class EliminateJoinByFkTest extends TestWithFeService implements MemoPatternMatc } @Test - void testNotNull() throws Exception { - addConstraint("Alter table foreign_not_null add constraint uk1 unique (id2)\n"); + void testNotNull() { String sql = "select pri.id1 from pri inner join foreign_not_null on pri.id1 = foreign_not_null.id2"; PlanChecker.from(connectContext) .analyze(sql) .rewrite() .nonMatch(logicalJoin()) .printlnTree(); - dropConstraint("Alter table foreign_not_null drop constraint uk1\n"); + + sql = "select foreign_not_null.id2 from pri inner join foreign_not_null on pri.id1 = foreign_not_null.id2"; + PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .nonMatch(logicalJoin()) + .printlnTree(); } @Test - void testNotNullWithPredicate() throws Exception { - addConstraint("Alter table foreign_not_null add constraint uk2 unique (id2)\n"); + void testNotNullWithPredicate() { String sql = "select pri.id1 from pri inner join foreign_not_null on pri.id1 = foreign_not_null.id2\n" + "where pri.id1 = 1"; PlanChecker.from(connectContext) .analyze(sql) .rewrite() .nonMatch(logicalJoin()) + .matches(logicalFilter().when(f -> { + Assertions.assertEquals("(id2 = 1)", f.getPredicate().toSql()); + return true; + })) + .printlnTree(); + sql = "select foreign_not_null.id2 from pri inner join foreign_not_null on pri.id1 = foreign_not_null.id2\n" + + "where pri.id1 = 1"; + PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .nonMatch(logicalJoin()) + .matches(logicalFilter().when(f -> { + Assertions.assertEquals("(id2 = 1)", f.getPredicate().toSql()); + return true; + })) .printlnTree(); - dropConstraint("Alter table foreign_not_null drop constraint uk2\n"); } @Test void testNull() throws Exception { - addConstraint("Alter table foreign_null add constraint uk unique (id3)\n"); String sql = "select pri.id1 from pri inner join foreign_null on pri.id1 = foreign_null.id3"; PlanChecker.from(connectContext) .analyze(sql) .rewrite() .nonMatch(logicalJoin()) + .matches(logicalFilter().when(f -> { + Assertions.assertEquals("( not id3 IS NULL)", f.getPredicate().toSql()); + return true; + })) + .printlnTree(); + sql = "select foreign_null.id3 from pri inner join foreign_null on pri.id1 = foreign_null.id3"; + PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .nonMatch(logicalJoin()) + .matches(logicalFilter().when(f -> { + Assertions.assertEquals("( not id3 IS NULL)", f.getPredicate().toSql()); + return true; + })) .printlnTree(); - dropConstraint("Alter table foreign_null drop constraint uk\n"); } @Test void testNullWithPredicate() throws Exception { - addConstraint("Alter table foreign_null add constraint uk unique (id3)\n"); String sql = "select pri.id1 from pri inner join foreign_null on pri.id1 = foreign_null.id3\n" + "where pri.id1 = 1"; PlanChecker.from(connectContext) .analyze(sql) .rewrite() .nonMatch(logicalJoin()) + .matches(logicalFilter().when(f -> { + Assertions.assertEquals("( not id3 IS NULL)", f.getExpressions().get(0).toSql()); + Assertions.assertEquals("(id3 = 1)", f.getExpressions().get(1).toSql()); + return true; + })) + .printlnTree(); + sql = "select id3 from pri inner join foreign_null on pri.id1 = foreign_null.id3\n" + + "where pri.id1 = 1"; + PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .nonMatch(logicalJoin()) + .matches(logicalFilter().when(f -> { + Assertions.assertEquals("( not id3 IS NULL)", f.getExpressions().get(0).toSql()); + Assertions.assertEquals("(id3 = 1)", f.getExpressions().get(1).toSql()); + return true; + })) .printlnTree(); - dropConstraint("Alter table foreign_null drop constraint uk\n"); } @Test - void testMultiJoin() throws Exception { - addConstraint("Alter table foreign_null add constraint uk_id3 unique (id3)\n"); - addConstraint("Alter table foreign_not_null add constraint uk_id2 unique (id2)\n"); + void testMultiJoinCanPassForeign() throws Exception { String sql = "select id1 from " + "foreign_null inner join foreign_not_null on id2 = id3\n" + "inner join pri on id1 = id3"; @@ -117,7 +161,35 @@ class EliminateJoinByFkTest extends TestWithFeService implements MemoPatternMatc .rewrite() .nonMatch(logicalOlapScan().when(scan -> scan.getTable().getName().equals("pri"))) .printlnTree(); - dropConstraint("Alter table foreign_null drop constraint uk_id3\n"); - dropConstraint("Alter table foreign_not_null drop constraint uk_id2"); + } + + @Test + void testMultiJoinCannotPassPrimary() throws Exception { + String sql = "select id1 from " + + "foreign_null " + + "inner join pri on id1 = id3\n" + + "inner join foreign_not_null on id2 = id3\n"; + PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .matches(logicalOlapScan().when(scan -> scan.getTable().getName().equals("pri"))) + .printlnTree(); + } + + @Test + void testOtherCond() { + String sql = "select pri.id1 from pri inner join foreign_null on pri.id1 > foreign_null.id3 \n" + + "where pri.id1 = 1"; + PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .matches(logicalOlapScan().when(scan -> scan.getTable().getName().equals("pri"))); + + sql = "select pri.id1 from pri inner join foreign_null on pri.id1 != foreign_null.id3 \n" + + "where pri.id1 = 1"; + PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .matches(logicalOlapScan().when(scan -> scan.getTable().getName().equals("pri"))); } } diff --git a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query23.out b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query23.out index d9254bbe921..c7563fa6bdb 100644 --- a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query23.out +++ b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query23.out @@ -24,35 +24,30 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----PhysicalCteProducer ( cteId=CTEId#2 ) ------PhysicalProject --------NestedLoopJoin[INNER_JOIN](cast(ssales as DOUBLE) > cast((0.9500 * tpcds_cmax) as DOUBLE)) -----------hashAgg[LOCAL] -------------PhysicalProject ---------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[ss_customer_sk] -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[store_sales] apply RFs: RF4 -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[customer] +----------hashAgg[GLOBAL] +------------PhysicalDistribute +--------------hashAgg[LOCAL] +----------------PhysicalProject +------------------filter(( not ss_customer_sk IS NULL)) +--------------------PhysicalOlapScan[store_sales] ----------PhysicalDistribute ------------PhysicalProject --------------hashAgg[GLOBAL] ----------------PhysicalDistribute ------------------hashAgg[LOCAL] --------------------PhysicalProject -----------------------hashAgg[LOCAL] -------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF3 c_customer_sk->[ss_customer_sk] -----------------------------PhysicalDistribute +----------------------hashAgg[GLOBAL] +------------------------PhysicalDistribute +--------------------------hashAgg[LOCAL] +----------------------------PhysicalProject ------------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF2 d_date_sk->[ss_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 RF3 +----------------------------------filter(( not ss_customer_sk IS NULL)) +------------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter(d_year IN (2000, 2001, 2002, 2003)) --------------------------------------PhysicalOlapScan[date_dim] -----------------------------PhysicalDistribute -------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[customer] ----PhysicalResultSink ------PhysicalLimit[GLOBAL] --------PhysicalLimit[LOCAL] @@ -67,11 +62,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) --------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) ----------------------PhysicalDistribute ------------------------PhysicalProject ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF6 c_customer_sk->[cs_bill_customer_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[cs_bill_customer_sk] ----------------------------PhysicalDistribute -------------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF5 d_date_sk->[cs_sold_date_sk] +------------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF3 d_date_sk->[cs_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF5 RF6 +----------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF3 RF4 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter((date_dim.d_moy = 7) and (date_dim.d_year = 2000)) @@ -86,11 +81,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) --------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) ----------------------PhysicalDistribute ------------------------PhysicalProject ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF8 c_customer_sk->[ws_bill_customer_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF6 c_customer_sk->[ws_bill_customer_sk] ----------------------------PhysicalDistribute -------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF7 d_date_sk->[ws_sold_date_sk] +------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF5 d_date_sk->[ws_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[web_sales] apply RFs: RF7 RF8 +----------------------------------PhysicalOlapScan[web_sales] apply RFs: RF5 RF6 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter((date_dim.d_moy = 7) and (date_dim.d_year = 2000)) diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/noStatsRfPrune/query23.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/noStatsRfPrune/query23.out index 4a2a4eee66f..0ee8af28ef8 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/noStatsRfPrune/query23.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/noStatsRfPrune/query23.out @@ -23,36 +23,30 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----PhysicalCteProducer ( cteId=CTEId#2 ) ------PhysicalProject --------NestedLoopJoin[INNER_JOIN](cast(ssales as DOUBLE) > cast((0.9500 * tpcds_cmax) as DOUBLE)) -----------hashAgg[LOCAL] -------------PhysicalProject ---------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[ss_customer_sk] -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[store_sales] apply RFs: RF4 -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[customer] +----------hashAgg[GLOBAL] +------------PhysicalDistribute +--------------hashAgg[LOCAL] +----------------PhysicalProject +------------------filter(( not ss_customer_sk IS NULL)) +--------------------PhysicalOlapScan[store_sales] ----------PhysicalDistribute ------------PhysicalProject --------------hashAgg[GLOBAL] ----------------PhysicalDistribute ------------------hashAgg[LOCAL] --------------------PhysicalProject -----------------------hashAgg[LOCAL] -------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF3 d_date_sk->[ss_sold_date_sk] +----------------------hashAgg[GLOBAL] +------------------------PhysicalDistribute +--------------------------hashAgg[LOCAL] ----------------------------PhysicalProject -------------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF2 c_customer_sk->[ss_customer_sk] ---------------------------------PhysicalDistribute -----------------------------------PhysicalProject -------------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 RF3 +------------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF2 d_date_sk->[ss_sold_date_sk] +--------------------------------PhysicalProject +----------------------------------filter(( not ss_customer_sk IS NULL)) +------------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject -------------------------------------PhysicalOlapScan[customer] -----------------------------PhysicalDistribute -------------------------------PhysicalProject ---------------------------------filter(d_year IN (2000, 2001, 2002, 2003)) -----------------------------------PhysicalOlapScan[date_dim] +------------------------------------filter(d_year IN (2000, 2001, 2002, 2003)) +--------------------------------------PhysicalOlapScan[date_dim] ----PhysicalResultSink ------PhysicalLimit[GLOBAL] --------PhysicalLimit[LOCAL] @@ -63,11 +57,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ------------------PhysicalProject --------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_item_sk = frequent_ss_items.item_sk)) otherCondition=() ----------------------PhysicalDistribute -------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF6 d_date_sk->[cs_sold_date_sk] ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF5 c_customer_sk->[cs_bill_customer_sk] +------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF4 d_date_sk->[cs_sold_date_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF3 c_customer_sk->[cs_bill_customer_sk] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF5 RF6 +--------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF3 RF4 ----------------------------PhysicalDistribute ------------------------------PhysicalProject --------------------------------PhysicalCteConsumer ( cteId=CTEId#2 ) @@ -81,11 +75,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ------------------PhysicalProject --------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_item_sk = frequent_ss_items.item_sk)) otherCondition=() ----------------------PhysicalDistribute -------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF8 d_date_sk->[ws_sold_date_sk] ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF7 c_customer_sk->[ws_bill_customer_sk] +------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF6 d_date_sk->[ws_sold_date_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF5 c_customer_sk->[ws_bill_customer_sk] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[web_sales] apply RFs: RF7 RF8 +--------------------------------PhysicalOlapScan[web_sales] apply RFs: RF5 RF6 ----------------------------PhysicalDistribute ------------------------------PhysicalProject --------------------------------PhysicalCteConsumer ( cteId=CTEId#2 ) diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/no_stats_shape/query23.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/no_stats_shape/query23.out index 21fdf044f74..b7577680eba 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/no_stats_shape/query23.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/no_stats_shape/query23.out @@ -23,36 +23,30 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----PhysicalCteProducer ( cteId=CTEId#2 ) ------PhysicalProject --------NestedLoopJoin[INNER_JOIN](cast(ssales as DOUBLE) > cast((0.9500 * tpcds_cmax) as DOUBLE)) -----------hashAgg[LOCAL] -------------PhysicalProject ---------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[ss_customer_sk] -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[store_sales] apply RFs: RF4 -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[customer] +----------hashAgg[GLOBAL] +------------PhysicalDistribute +--------------hashAgg[LOCAL] +----------------PhysicalProject +------------------filter(( not ss_customer_sk IS NULL)) +--------------------PhysicalOlapScan[store_sales] ----------PhysicalDistribute ------------PhysicalProject --------------hashAgg[GLOBAL] ----------------PhysicalDistribute ------------------hashAgg[LOCAL] --------------------PhysicalProject -----------------------hashAgg[LOCAL] -------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF3 d_date_sk->[ss_sold_date_sk] +----------------------hashAgg[GLOBAL] +------------------------PhysicalDistribute +--------------------------hashAgg[LOCAL] ----------------------------PhysicalProject -------------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF2 c_customer_sk->[ss_customer_sk] ---------------------------------PhysicalDistribute -----------------------------------PhysicalProject -------------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 RF3 +------------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF2 d_date_sk->[ss_sold_date_sk] +--------------------------------PhysicalProject +----------------------------------filter(( not ss_customer_sk IS NULL)) +------------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject -------------------------------------PhysicalOlapScan[customer] -----------------------------PhysicalDistribute -------------------------------PhysicalProject ---------------------------------filter(d_year IN (2000, 2001, 2002, 2003)) -----------------------------------PhysicalOlapScan[date_dim] +------------------------------------filter(d_year IN (2000, 2001, 2002, 2003)) +--------------------------------------PhysicalOlapScan[date_dim] ----PhysicalResultSink ------PhysicalLimit[GLOBAL] --------PhysicalLimit[LOCAL] @@ -63,11 +57,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ------------------PhysicalProject --------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_item_sk = frequent_ss_items.item_sk)) otherCondition=() ----------------------PhysicalDistribute -------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF6 d_date_sk->[cs_sold_date_sk] ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF5 c_customer_sk->[cs_bill_customer_sk] +------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF4 d_date_sk->[cs_sold_date_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF3 c_customer_sk->[cs_bill_customer_sk] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF5 RF6 +--------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF3 RF4 ----------------------------PhysicalDistribute ------------------------------PhysicalProject --------------------------------PhysicalCteConsumer ( cteId=CTEId#2 ) @@ -81,11 +75,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ------------------PhysicalProject --------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_item_sk = frequent_ss_items.item_sk)) otherCondition=() ----------------------PhysicalDistribute -------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF8 d_date_sk->[ws_sold_date_sk] ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF7 c_customer_sk->[ws_bill_customer_sk] +------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF6 d_date_sk->[ws_sold_date_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF5 c_customer_sk->[ws_bill_customer_sk] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[web_sales] apply RFs: RF7 RF8 +--------------------------------PhysicalOlapScan[web_sales] apply RFs: RF5 RF6 ----------------------------PhysicalDistribute ------------------------------PhysicalProject --------------------------------PhysicalCteConsumer ( cteId=CTEId#2 ) diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/rf_prune/query23.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/rf_prune/query23.out index eb0339f7010..e1aafd4c5a1 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/rf_prune/query23.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/rf_prune/query23.out @@ -24,35 +24,30 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----PhysicalCteProducer ( cteId=CTEId#2 ) ------PhysicalProject --------NestedLoopJoin[INNER_JOIN](cast(ssales as DOUBLE) > cast((0.9500 * tpcds_cmax) as DOUBLE)) -----------hashAgg[LOCAL] -------------PhysicalProject ---------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[ss_customer_sk] -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[store_sales] apply RFs: RF4 -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[customer] +----------hashAgg[GLOBAL] +------------PhysicalDistribute +--------------hashAgg[LOCAL] +----------------PhysicalProject +------------------filter(( not ss_customer_sk IS NULL)) +--------------------PhysicalOlapScan[store_sales] ----------PhysicalDistribute ------------PhysicalProject --------------hashAgg[GLOBAL] ----------------PhysicalDistribute ------------------hashAgg[LOCAL] --------------------PhysicalProject -----------------------hashAgg[LOCAL] -------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF3 c_customer_sk->[ss_customer_sk] -----------------------------PhysicalDistribute +----------------------hashAgg[GLOBAL] +------------------------PhysicalDistribute +--------------------------hashAgg[LOCAL] +----------------------------PhysicalProject ------------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF2 d_date_sk->[ss_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 RF3 +----------------------------------filter(( not ss_customer_sk IS NULL)) +------------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter(d_year IN (2000, 2001, 2002, 2003)) --------------------------------------PhysicalOlapScan[date_dim] -----------------------------PhysicalDistribute -------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[customer] ----PhysicalResultSink ------PhysicalLimit[GLOBAL] --------PhysicalLimit[LOCAL] @@ -67,11 +62,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) --------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) ----------------------PhysicalDistribute ------------------------PhysicalProject ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF6 c_customer_sk->[cs_bill_customer_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[cs_bill_customer_sk] ----------------------------PhysicalDistribute -------------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF5 d_date_sk->[cs_sold_date_sk] +------------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF3 d_date_sk->[cs_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF5 RF6 +----------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF3 RF4 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter((date_dim.d_moy = 5) and (date_dim.d_year = 2000)) @@ -86,11 +81,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) --------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) ----------------------PhysicalDistribute ------------------------PhysicalProject ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF8 c_customer_sk->[ws_bill_customer_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF6 c_customer_sk->[ws_bill_customer_sk] ----------------------------PhysicalDistribute -------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF7 d_date_sk->[ws_sold_date_sk] +------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF5 d_date_sk->[ws_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[web_sales] apply RFs: RF7 RF8 +----------------------------------PhysicalOlapScan[web_sales] apply RFs: RF5 RF6 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter((date_dim.d_moy = 5) and (date_dim.d_year = 2000)) diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query23.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query23.out index eefbd37e7df..54d92b454d3 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query23.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query23.out @@ -24,35 +24,30 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----PhysicalCteProducer ( cteId=CTEId#2 ) ------PhysicalProject --------NestedLoopJoin[INNER_JOIN](cast(ssales as DOUBLE) > cast((0.9500 * tpcds_cmax) as DOUBLE)) -----------hashAgg[LOCAL] -------------PhysicalProject ---------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[ss_customer_sk] -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[store_sales] apply RFs: RF4 -----------------PhysicalDistribute -------------------PhysicalProject ---------------------PhysicalOlapScan[customer] +----------hashAgg[GLOBAL] +------------PhysicalDistribute +--------------hashAgg[LOCAL] +----------------PhysicalProject +------------------filter(( not ss_customer_sk IS NULL)) +--------------------PhysicalOlapScan[store_sales] ----------PhysicalDistribute ------------PhysicalProject --------------hashAgg[GLOBAL] ----------------PhysicalDistribute ------------------hashAgg[LOCAL] --------------------PhysicalProject -----------------------hashAgg[LOCAL] -------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_customer_sk = customer.c_customer_sk)) otherCondition=() build RFs:RF3 c_customer_sk->[ss_customer_sk] -----------------------------PhysicalDistribute +----------------------hashAgg[GLOBAL] +------------------------PhysicalDistribute +--------------------------hashAgg[LOCAL] +----------------------------PhysicalProject ------------------------------hashJoin[INNER_JOIN] hashCondition=((store_sales.ss_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF2 d_date_sk->[ss_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 RF3 +----------------------------------filter(( not ss_customer_sk IS NULL)) +------------------------------------PhysicalOlapScan[store_sales] apply RFs: RF2 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter(d_year IN (2000, 2001, 2002, 2003)) --------------------------------------PhysicalOlapScan[date_dim] -----------------------------PhysicalDistribute -------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[customer] ----PhysicalResultSink ------PhysicalLimit[GLOBAL] --------PhysicalLimit[LOCAL] @@ -67,11 +62,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) --------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) ----------------------PhysicalDistribute ------------------------PhysicalProject ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF6 c_customer_sk->[cs_bill_customer_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((catalog_sales.cs_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF4 c_customer_sk->[cs_bill_customer_sk] ----------------------------PhysicalDistribute -------------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF5 d_date_sk->[cs_sold_date_sk] +------------------------------hashJoin[INNER_JOIN] hashCondition=((catalog_sales.cs_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF3 d_date_sk->[cs_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF5 RF6 +----------------------------------PhysicalOlapScan[catalog_sales] apply RFs: RF3 RF4 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter((date_dim.d_moy = 5) and (date_dim.d_year = 2000)) @@ -86,11 +81,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) --------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) ----------------------PhysicalDistribute ------------------------PhysicalProject ---------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF8 c_customer_sk->[ws_bill_customer_sk] +--------------------------hashJoin[LEFT_SEMI_JOIN] hashCondition=((web_sales.ws_bill_customer_sk = best_ss_customer.c_customer_sk)) otherCondition=() build RFs:RF6 c_customer_sk->[ws_bill_customer_sk] ----------------------------PhysicalDistribute -------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF7 d_date_sk->[ws_sold_date_sk] +------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_sold_date_sk = date_dim.d_date_sk)) otherCondition=() build RFs:RF5 d_date_sk->[ws_sold_date_sk] --------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[web_sales] apply RFs: RF7 RF8 +----------------------------------PhysicalOlapScan[web_sales] apply RFs: RF5 RF6 --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------filter((date_dim.d_moy = 5) and (date_dim.d_year = 2000)) --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org