From 0aa1733e61b3cc0d45c8d4ffdaaf38532ce4eda4 Mon Sep 17 00:00:00 2001 From: minghong Date: Thu, 23 Apr 2026 14:47:05 +0800 Subject: [PATCH 1/2] [fix](eager-agg) push aggregation down through filter (#62669) Issue Number: None Related PR: None push aggregation down through filter, if filter.child() is not Scan None - Test: Manual test - Regression test case updated; out refreshed in working tree - Behavior changed: Yes (eager agg can safely push through filter while preserving filter-required slots) - Does this need documentation: No --- .../eageraggregation/EagerAggRewriter.java | 23 +++ .../EagerAggRewriterTest.java | 74 +++++++++ .../data/nereids_p0/eager_agg/eager_agg.out | 73 +++++++++ .../nereids_p0/eager_agg/eager_agg.groovy | 152 ++++++++++++++++++ 4 files changed, 322 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java index 87050b5bbdfe22..22bf33a99f73fe 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriter.java @@ -54,6 +54,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * eager aggregation @@ -505,6 +506,28 @@ public Plan visitLogicalAggregate(LogicalAggregate agg, PushDown @Override public Plan visitLogicalFilter(LogicalFilter filter, PushDownAggContext context) { + if (filter.child() instanceof LogicalRelation) { + return genAggregate(filter, context); + } + if (filter.getConjuncts().stream().anyMatch(Expression::containsUniqueFunction)) { + return genAggregate(filter, context); + } + List filterInputSlots = filter.getInputSlots().stream() + .map(slot -> (SlotReference) slot) + .collect(Collectors.toList()); + List childGroupKeys = Stream.concat( + context.getGroupKeys().stream(), + filterInputSlots.stream()) + .distinct() + .collect(Collectors.toList()); + PushDownAggContext childContext = context.withGroupKeys(childGroupKeys); + if (!childContext.isValid()) { + return genAggregate(filter, context); + } + Plan newChild = filter.child().accept(this, childContext); + if (newChild != filter.child()) { + return filter.withChildren(newChild); + } return genAggregate(filter, context); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java index 4b0561ccd0f894..fdb171abf8bc67 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/EagerAggRewriterTest.java @@ -17,10 +17,14 @@ package org.apache.doris.nereids.rules.rewrite.eageraggregation; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; +import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.util.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 EagerAggRewriterTest extends TestWithFeService implements MemoPatternMatchSupported { @@ -311,4 +315,74 @@ void testAsofJoinNotPushAgg() { connectContext.getSessionVariable().setDisableJoinReorder(false); } } + + + @Test + void testUniqueFunctionFilterBlocksPushDownThroughFilter() { + connectContext.getSessionVariable().setEagerAggregationMode(1); + connectContext.getSessionVariable().setDisableJoinReorder(true); + try { + String sql = "select count(s.name1), t2.id2" + + " from (select * from (select id1, name as name1 from t1) s1 where random() < 0.5) s" + + " join t2 on s.id1 = t2.id2 group by t2.id2"; + Plan plan = PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .getPlan(); + Assertions.assertEquals(2, countPlans(plan, LogicalAggregate.class), plan.treeString()); + LogicalFilter filter = findFirstPlan(plan, LogicalFilter.class); + Assertions.assertNotNull(filter, plan.treeString()); + Assertions.assertFalse(containsPlan(filter.child(), LogicalAggregate.class), plan.treeString()); + } finally { + connectContext.getSessionVariable().setEagerAggregationMode(0); + connectContext.getSessionVariable().setDisableJoinReorder(false); + } + } + + @Test + void testInvalidFilterContextFallsBackToCurrentFilter() { + connectContext.getSessionVariable().setEagerAggregationMode(1); + connectContext.getSessionVariable().setDisableJoinReorder(true); + try { + String sql = "select count(s.name1), t2.id2" + + " from (select * from (select id1, name as name1 from t1) s1 where s1.name1 is not null) s" + + " join t2 on s.id1 = t2.id2 group by t2.id2"; + Plan plan = PlanChecker.from(connectContext) + .analyze(sql) + .rewrite() + .getPlan(); + Assertions.assertEquals(2, countPlans(plan, LogicalAggregate.class), plan.treeString()); + LogicalFilter filter = findFirstPlan(plan, LogicalFilter.class); + Assertions.assertNotNull(filter, plan.treeString()); + Assertions.assertFalse(containsPlan(filter.child(), LogicalAggregate.class), plan.treeString()); + } finally { + connectContext.getSessionVariable().setEagerAggregationMode(0); + connectContext.getSessionVariable().setDisableJoinReorder(false); + } + } + + private int countPlans(Plan plan, Class clazz) { + int count = clazz.isInstance(plan) ? 1 : 0; + for (Plan child : plan.children()) { + count += countPlans(child, clazz); + } + return count; + } + + private boolean containsPlan(Plan plan, Class clazz) { + return countPlans(plan, clazz) > 0; + } + + private T findFirstPlan(Plan plan, Class clazz) { + if (clazz.isInstance(plan)) { + return clazz.cast(plan); + } + for (Plan child : plan.children()) { + T matched = findFirstPlan(child, clazz); + if (matched != null) { + return matched; + } + } + return null; + } } diff --git a/regression-test/data/nereids_p0/eager_agg/eager_agg.out b/regression-test/data/nereids_p0/eager_agg/eager_agg.out index 731f2e9bd9eda7..0002020e14a781 100644 --- a/regression-test/data/nereids_p0/eager_agg/eager_agg.out +++ b/regression-test/data/nereids_p0/eager_agg/eager_agg.out @@ -311,3 +311,76 @@ Used: UnUsed: SyntaxError: leading({ ss broadcast dt } broadcast ws) Msg:can not find table: ws +-- !check_sum_literal_right_join_not_push -- +PhysicalResultSink +--hashAgg[GLOBAL] +----hashAgg[LOCAL] +------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.val = c.val) and (b.id2 = c.id2)) otherCondition=() +--------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.id = b.id)) otherCondition=() +----------PhysicalOlapScan[eager_agg_t1(a)] +----------PhysicalOlapScan[eager_agg_t2(b)] +--------PhysicalOlapScan[eager_agg_t3(c)] + +-- !check_sum_literal_left_join_not_push -- +PhysicalResultSink +--hashAgg[GLOBAL] +----hashAgg[LOCAL] +------hashJoin[LEFT_OUTER_JOIN] hashCondition=((date_dim.d_date_sk = store_sales.ss_sold_date_sk)) otherCondition=() +--------hashAgg[GLOBAL] +----------hashAgg[LOCAL] +------------PhysicalOlapScan[store_sales] +--------PhysicalOlapScan[date_dim] + +-- !check_min_literal_right_join_not_push -- +PhysicalResultSink +--hashAgg[GLOBAL] +----hashAgg[LOCAL] +------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.val = c.val) and (b.id2 = c.id2)) otherCondition=() +--------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((a.id = b.id)) otherCondition=() +----------PhysicalOlapScan[eager_agg_t1(a)] +----------PhysicalOlapScan[eager_agg_t2(b)] +--------PhysicalOlapScan[eager_agg_t3(c)] + +-- !check_max_literal_left_join_not_push -- +PhysicalResultSink +--hashAgg[GLOBAL] +----hashAgg[LOCAL] +------hashJoin[LEFT_OUTER_JOIN] hashCondition=((date_dim.d_date_sk = store_sales.ss_sold_date_sk)) otherCondition=() +--------hashAgg[GLOBAL] +----------hashAgg[LOCAL] +------------PhysicalOlapScan[store_sales] +--------PhysicalOlapScan[date_dim] + +-- !sum_literal_right_join_eager_off -- +\N 4 +10 2 + +-- !sum_literal_right_join_eager_on -- +\N 4 +10 2 + +-- !min_literal_right_join_eager_on -- +\N 1 +10 1 + +-- !max_literal_right_join_eager_on -- +\N 3 +10 3 + +-- !check_filter_slots_preserved_pushdown -- +PhysicalResultSink +--hashAgg[GLOBAL] +----filter(OR[( not (id = 1)),id IS NULL]) +------hashJoin[LEFT_OUTER_JOIN] hashCondition=((a.id = b.id)) otherCondition=() +--------hashAgg[GLOBAL] +----------PhysicalOlapScan[eager_agg_filter_t1(a)] +--------PhysicalOlapScan[eager_agg_filter_t2(b)] + +Hint log: +Used: [broadcast]_1 +UnUsed: +SyntaxError: + +-- !filter_slots_preserved_eager_on -- +2 20 + diff --git a/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy b/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy index 4f9653829b3954..5d738a962d6c98 100644 --- a/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy +++ b/regression-test/suites/nereids_p0/eager_agg/eager_agg.groovy @@ -411,4 +411,156 @@ suite("eager_agg") { ) t group by d_year; """ + + // ========================================================================= + // Tests for agg(literal) on nullable side of outer joins + // sum(literal), min(literal), max(literal) should NOT be pushed to the + // nullable side of outer joins because unmatched rows lose their contribution. + // ========================================================================= + + sql """ + drop table if exists eager_agg_t1; + drop table if exists eager_agg_t2; + drop table if exists eager_agg_t3; + drop table if exists eager_agg_filter_t1; + drop table if exists eager_agg_filter_t2; + + CREATE TABLE eager_agg_t1 ( + id INT NOT NULL, + val INT + ) DISTRIBUTED BY HASH(id) BUCKETS 1 + PROPERTIES ('replication_num' = '1'); + + CREATE TABLE eager_agg_t2 ( + id INT NOT NULL, + id2 INT NOT NULL + ) DISTRIBUTED BY HASH(id) BUCKETS 1 + PROPERTIES ('replication_num' = '1'); + + CREATE TABLE eager_agg_t3 ( + id2 INT NOT NULL, + val INT + ) DISTRIBUTED BY HASH(id2) BUCKETS 1 + PROPERTIES ('replication_num' = '1'); + + CREATE TABLE eager_agg_filter_t1 ( + id INT NOT NULL, + flag INT NOT NULL, + v INT NOT NULL + ) DISTRIBUTED BY HASH(id) BUCKETS 1 + PROPERTIES ('replication_num' = '1'); + + CREATE TABLE eager_agg_filter_t2 ( + id INT NOT NULL + ) DISTRIBUTED BY HASH(id) BUCKETS 1 + PROPERTIES ('replication_num' = '1'); + + INSERT INTO eager_agg_t1 VALUES (1, 10); + INSERT INTO eager_agg_t2 VALUES (1, 100), (2, 200); + INSERT INTO eager_agg_t3 VALUES (100, 10), (200, 20), (300, 30); + INSERT INTO eager_agg_filter_t1 VALUES (1, 0, 10), (2, 1, 20); + INSERT INTO eager_agg_filter_t2 VALUES (1); + """ + + // sum(literal) should NOT be pushed below RIGHT JOIN to the nullable left side + qt_check_sum_literal_right_join_not_push """ + explain shape plan + select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/ + a.val, sum(2) as s + from eager_agg_t1 as a + right join eager_agg_t2 as b on a.id = b.id + right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val + group by a.val; + """ + + // sum(literal) should NOT be pushed below LEFT JOIN to the nullable right side + qt_check_sum_literal_left_join_not_push """ + explain shape plan + select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/ + ss_sales_price, sum(2) as s + from store_sales + left join date_dim on d_date_sk = ss_sold_date_sk + group by ss_sales_price; + """ + + // min(literal) should NOT be pushed to nullable side of RIGHT JOIN + qt_check_min_literal_right_join_not_push """ + explain shape plan + select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/ + a.val, min(1) as m + from eager_agg_t1 as a + right join eager_agg_t2 as b on a.id = b.id + right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val + group by a.val; + """ + + // max(literal) should NOT be pushed to nullable side of LEFT JOIN + qt_check_max_literal_left_join_not_push """ + explain shape plan + select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/ + ss_sales_price, max(3) as m + from store_sales + left join date_dim on d_date_sk = ss_sold_date_sk + group by ss_sales_price; + """ + + // Execution tests: verify eager agg produces correct results for outer join + literal agg + order_qt_sum_literal_right_join_eager_off """ + select /*+SET_VAR(eager_aggregation_mode=-1)*/ /*+ leading(a b c) */ + a.val, sum(2) as s + from eager_agg_t1 as a + right join eager_agg_t2 as b on a.id = b.id + right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val + group by a.val + order by a.val; + """ + + order_qt_sum_literal_right_join_eager_on """ + select /*+SET_VAR(eager_aggregation_mode=1)*/ /*+ leading(a b c) */ + a.val, sum(2) as s + from eager_agg_t1 as a + right join eager_agg_t2 as b on a.id = b.id + right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val + group by a.val + order by a.val; + """ + + order_qt_min_literal_right_join_eager_on """ + select /*+SET_VAR(eager_aggregation_mode=1)*/ /*+ leading(a b c) */ + a.val, min(1) as m + from eager_agg_t1 as a + right join eager_agg_t2 as b on a.id = b.id + right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val + group by a.val + order by a.val; + """ + + order_qt_max_literal_right_join_eager_on """ + select /*+SET_VAR(eager_aggregation_mode=1)*/ /*+ leading(a b c) */ + a.val, max(3) as m + from eager_agg_t1 as a + right join eager_agg_t2 as b on a.id = b.id + right join eager_agg_t3 as c on b.id2 = c.id2 and a.val = c.val + group by a.val + order by a.val; + """ + + qt_check_filter_slots_preserved_pushdown """ + explain shape plan + select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/ + a.id, sum(a.v) as s + from eager_agg_filter_t1 as a + left join[broadcast] eager_agg_filter_t2 as b on a.id = b.id + where b.id <> 1 or b.id is null + group by a.id; + """ + + order_qt_filter_slots_preserved_eager_on """ + select /*+SET_VAR(eager_aggregation_mode=1, disable_join_reorder = true)*/ + a.id, sum(a.v) as s + from eager_agg_filter_t1 as a + left join[broadcast] eager_agg_filter_t2 as b on a.id = b.id + where b.id <> 1 or b.id is null + group by a.id; + """ } From 87d5318ed67610f4dac538c1370a1673fe925d27 Mon Sep 17 00:00:00 2001 From: englefly Date: Fri, 22 May 2026 17:05:03 +0800 Subject: [PATCH 2/2] fix --- .../data/nereids_p0/eager_agg/eager_agg.out | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/regression-test/data/nereids_p0/eager_agg/eager_agg.out b/regression-test/data/nereids_p0/eager_agg/eager_agg.out index 0002020e14a781..856116a079c3f2 100644 --- a/regression-test/data/nereids_p0/eager_agg/eager_agg.out +++ b/regression-test/data/nereids_p0/eager_agg/eager_agg.out @@ -7,9 +7,9 @@ PhysicalResultSink --------hashAgg[GLOBAL] ----------hashAgg[LOCAL] ------------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() ---------------PhysicalOlapScan[store_sales] ---------------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +--------------PhysicalOlapScan[store_sales(ss)] +--------------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -28,9 +28,9 @@ PhysicalResultSink --------hashAgg[GLOBAL] ----------hashAgg[LOCAL] ------------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() ---------------PhysicalOlapScan[store_sales] ---------------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +--------------PhysicalOlapScan[store_sales(ss)] +--------------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -49,9 +49,9 @@ PhysicalResultSink --------hashAgg[GLOBAL] ----------hashAgg[LOCAL] ------------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() ---------------PhysicalOlapScan[store_sales] ---------------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +--------------PhysicalOlapScan[store_sales(ss)] +--------------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -68,9 +68,9 @@ PhysicalResultSink ----hashAgg[LOCAL] ------hashJoin[INNER_JOIN] hashCondition=((dt.d_date_sk = ss.ss_sold_date_sk)) otherCondition=() --------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() -----------PhysicalOlapScan[store_sales] -----------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +----------PhysicalOlapScan[store_sales(ss)] +----------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -87,11 +87,11 @@ PhysicalResultSink ----hashAgg[LOCAL] ------hashJoin[INNER_JOIN] hashCondition=((dt.d_date_sk = ss.ss_sold_date_sk)) otherCondition=() --------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() -----------PhysicalOlapScan[store_sales] +----------PhysicalOlapScan[store_sales(ss)] ----------hashAgg[GLOBAL] ------------hashAgg[LOCAL] ---------------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +--------------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -110,9 +110,9 @@ PhysicalResultSink --------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() ----------hashAgg[GLOBAL] ------------hashAgg[LOCAL] ---------------PhysicalOlapScan[store_sales] -----------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +--------------PhysicalOlapScan[store_sales(ss)] +----------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -131,9 +131,9 @@ PhysicalResultSink --------hashAgg[GLOBAL] ----------hashAgg[LOCAL] ------------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() ---------------PhysicalOlapScan[store_sales] ---------------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +--------------PhysicalOlapScan[store_sales(ss)] +--------------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -152,9 +152,9 @@ PhysicalResultSink --------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() ----------hashAgg[GLOBAL] ------------hashAgg[LOCAL] ---------------PhysicalOlapScan[store_sales] -----------PhysicalOlapScan[web_sales] ---------PhysicalOlapScan[date_dim] +--------------PhysicalOlapScan[store_sales(ss)] +----------PhysicalOlapScan[web_sales(ws)] +--------PhysicalOlapScan[date_dim(dt)] Hint log: Used: leading({ ss broadcast ws } broadcast dt ) @@ -173,9 +173,9 @@ PhysicalResultSink --------hashAgg[GLOBAL] ----------hashAgg[LOCAL] ------------hashJoin[INNER_JOIN] hashCondition=((dt.d_date_sk = ss.ss_sold_date_sk)) otherCondition=() ---------------PhysicalOlapScan[store_sales] ---------------PhysicalOlapScan[date_dim] ---------PhysicalOlapScan[web_sales] +--------------PhysicalOlapScan[store_sales(ss)] +--------------PhysicalOlapScan[date_dim(dt)] +--------PhysicalOlapScan[web_sales(ws)] Hint log: Used: leading({ ss broadcast dt } broadcast ws ) @@ -197,9 +197,9 @@ PhysicalResultSink --------hashJoin[INNER_JOIN] hashCondition=((dt.d_date_sk = ss.ss_sold_date_sk)) otherCondition=() ----------hashAgg[GLOBAL] ------------hashAgg[LOCAL] ---------------PhysicalOlapScan[store_sales] -----------PhysicalOlapScan[date_dim] ---------PhysicalOlapScan[web_sales] +--------------PhysicalOlapScan[store_sales(ss)] +----------PhysicalOlapScan[date_dim(dt)] +--------PhysicalOlapScan[web_sales(ws)] Hint log: Used: leading({ ss broadcast dt } broadcast ws ) @@ -266,11 +266,11 @@ PhysicalResultSink ------hashAgg[LOCAL] --------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() ----------hashJoin[INNER_JOIN] hashCondition=((dt.d_date_sk = ss.ss_sold_date_sk)) otherCondition=() -------------PhysicalOlapScan[store_sales] +------------PhysicalOlapScan[store_sales(ss)] ------------hashAgg[GLOBAL] --------------hashAgg[LOCAL] -----------------PhysicalOlapScan[date_dim] -----------PhysicalOlapScan[web_sales] +----------------PhysicalOlapScan[date_dim(dt)] +----------PhysicalOlapScan[web_sales(ws)] Hint log: Used: leading({ ss broadcast dt } broadcast ws ) @@ -287,9 +287,9 @@ PhysicalResultSink ----hashAgg[LOCAL] ------hashJoin[INNER_JOIN] hashCondition=((ss.ss_item_sk = ws.ws_item_sk)) otherCondition=() --------hashJoin[INNER_JOIN] hashCondition=((dt.d_date_sk = ss.ss_sold_date_sk)) otherCondition=() -----------PhysicalOlapScan[store_sales] -----------PhysicalOlapScan[date_dim] ---------PhysicalOlapScan[web_sales] +----------PhysicalOlapScan[store_sales(ss)] +----------PhysicalOlapScan[date_dim(dt)] +--------PhysicalOlapScan[web_sales(ws)] Hint log: Used: leading({ ss broadcast dt } broadcast ws ) @@ -302,8 +302,8 @@ PhysicalResultSink ----hashAgg[LOCAL] ------PhysicalUnion --------hashJoin[INNER_JOIN] hashCondition=((dt.d_date_sk = ss.ss_sold_date_sk)) otherCondition=() -----------PhysicalOlapScan[store_sales] -----------PhysicalOlapScan[date_dim] +----------PhysicalOlapScan[store_sales(ss)] +----------PhysicalOlapScan[date_dim(dt)] --------PhysicalOlapScan[date_dim] Hint log: