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

HappenLee pushed a commit to branch opt_perf_4.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/opt_perf_4.1 by this push:
     new 97eddc7008f [enhance] Pick fall back fix and take string into account 
(#65799)
97eddc7008f is described below

commit 97eddc7008f63dfa97ee63fc02a916803708ff3d
Author: feiniaofeiafei <[email protected]>
AuthorDate: Mon Jul 20 11:32:22 2026 +0800

    [enhance] Pick fall back fix and take string into account (#65799)
    
    - Adjust the “large join” threshold by increasing the build-side
    row-count limit from 400K to 1M.
    - Allow aggregation to continue pushing down to the current join branch
    when the opposite subtree is large or outputs String/Character types, so
    that data participating in the join can be reduced earlier.
    - Tighten aggregation benefit evaluation: treat Group By keys with NDV >
    rowCount / 10 as having extremely low aggregation benefit; for
    multi-column Group By, skip aggregation pushdown if any key falls into
    this category, avoiding low-benefit pushdown caused by high cardinality.
    - Propagate a “bottom small broadcast join” marker in the pushdown
    context and apply stricter checks on the probe side: reject pushdown
    when Group By column statistics are unknown, or when any Group By key is
    estimated to reduce rows by less than 1000×.
    - Extend aggregation pushdown traversal to support passing through
    LogicalAggregate and LogicalIntersect nodes.
---
 .../rewrite/eageraggregation/EagerAggRewriter.java | 54 ++++++++++++++++++----
 .../eageraggregation/PushDownAggContext.java       | 17 +++++--
 .../eageraggregation/PushDownAggregation.java      |  3 ++
 .../eageraggregation/EagerAggRewriterTest.java     |  4 +-
 4 files changed, 61 insertions(+), 17 deletions(-)

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 91721adf935..c947a573153 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
@@ -87,10 +87,12 @@ import java.util.stream.Stream;
  *         ->T2(D)
  */
 public class EagerAggRewriter extends DefaultPlanRewriter<PushDownAggContext> {
-    public static final int BIG_JOIN_BUILD_SIZE = 400_000;
+    public static final int BIG_JOIN_BUILD_SIZE = 1_000_000;
     private static final double LOWER_AGGREGATE_EFFECT_COEFFICIENT = 10000;
     private static final double LOW_AGGREGATE_EFFECT_COEFFICIENT = 1000;
     private static final double MEDIUM_AGGREGATE_EFFECT_COEFFICIENT = 100;
+    private static final double HIGH_AGGREGATE_EFFECT_COEFFICIENT = 10;
+    private static final double SMALL_BROADCAST_REJECT_COEFFICIENT = 1000;
     private static final String JOIN_CNT = "joinCnt";
     private final StatsDerive derive = new StatsDerive(false);
 
@@ -110,9 +112,9 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
             }
         }
         ConnectContext connectContext = 
context.getCascadesContext().getConnectContext();
+        boolean isSmallBroadcastBottomJoin = isSmallBroadcastJoin(join, 
connectContext) && isBottomJoin(join);
         if (context.isPassThroughJoinOrUnion() && 
connectContext.getSessionVariable().eagerAggregationOnBroadcastJoin
-                && isSmallBroadcastJoin(join, connectContext) && 
isBottomJoin(join)
-                && !outputStringType(join.right())) {
+                && isSmallBroadcastBottomJoin && 
!outputStringType(join.right())) {
             Plan aggOnJoin = genAggregate(join, context);
             if (aggOnJoin != join) {
                 return aggOnJoin;
@@ -157,15 +159,16 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
             }
         }
 
-        boolean passThroughBigJoin = isPassThroughBigJoin(join, context);
         boolean leftNeedOutputCount = needOutputCountForJoinChild(join, 
toLeft, toRight,
                 context.needOutputCount(), rightFuncs);
         boolean rightNeedOutputCount = needOutputCountForJoinChild(join, 
toRight, toLeft,
                 context.needOutputCount(), leftFuncs);
         Optional<PushDownAggContext> leftChildContext = toLeft ? 
Optional.ofNullable(context.forOneBranch(leftFuncs,
-                leftAliasMap, leftChildGroupByKeys, passThroughBigJoin, 
leftNeedOutputCount)) : Optional.empty();
+                leftAliasMap, leftChildGroupByKeys, 
isPassThroughHeavyJoin(join.right(), context),
+                leftNeedOutputCount, isSmallBroadcastBottomJoin)) : 
Optional.empty();
         Optional<PushDownAggContext> rightChildContext = toRight ? 
Optional.ofNullable(context.forOneBranch(rightFuncs,
-                rightAliasMap, rightChildGroupByKeys, passThroughBigJoin, 
rightNeedOutputCount)) : Optional.empty();
+                rightAliasMap, rightChildGroupByKeys, 
isPassThroughHeavyJoin(join.left(), context),
+                rightNeedOutputCount, false)) : Optional.empty();
 
         Plan newLeft = join.left();
         Plan newRight = join.right();
@@ -191,6 +194,18 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
         return newJoin;
     }
 
+    private boolean isPassThroughHeavyJoin(Plan joinChild, PushDownAggContext 
context) {
+        if (context.isPassThroughBigJoin() || 
SessionVariable.getEagerAggregationMode() > 0) {
+            return true;
+        } else {
+            Statistics stats = joinChild.getStats();
+            if (stats == null) {
+                stats = joinChild.accept(derive, new 
StatsDerive.DeriveContext());
+            }
+            return stats.getRowCount() > BIG_JOIN_BUILD_SIZE || 
outputStringType(joinChild);
+        }
+    }
+
     private boolean outputStringType(Plan plan) {
         return plan.getOutput().stream().anyMatch(slot -> slot.getDataType() 
instanceof CharacterType);
     }
@@ -434,7 +449,8 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
         PushDownAggContext newContext = new PushDownAggContext(aggFunctions, 
groupKeys, aliasMap,
                 context.getCascadesContext(), context.isPassThroughBigJoin(),
                 context.hasDecomposedAggIf, newHasCaseWhen,
-                context.getBilateralState(), context.needOutputCount(), 
context.isPassThroughJoinOrUnion());
+                context.getBilateralState(), context.needOutputCount(), 
context.isPassThroughJoinOrUnion(),
+                context.isSmallBroadcastBottomJoin());
         return newContext;
     }
 
@@ -565,7 +581,7 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
             PushDownAggContext contextForChild = new 
PushDownAggContext(aggFunctionsForChild, groupKeysForChild,
                     aliasMapForChild, context.getCascadesContext(),
                     context.isPassThroughBigJoin(), 
context.hasDecomposedAggIf, context.hasCaseWhen,
-                    context.getBilateralState(), context.needOutputCount(), 
true);
+                    context.getBilateralState(), context.needOutputCount(), 
true, false);
             inheritHintActionsToUnionChild(context, contextForChild, 
aggFunctionsForChild);
             Plan newChild = child.accept(this, contextForChild);
             if (newChild != child) {
@@ -1272,8 +1288,9 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
         List<ColumnStatistic> lower = Lists.newArrayList();
         List<ColumnStatistic> medium = Lists.newArrayList();
         List<ColumnStatistic> high = Lists.newArrayList();
+        List<ColumnStatistic> extremelyHigh = Lists.newArrayList();
 
-        List<ColumnStatistic>[] cards = new List[] { lower, medium, high };
+        List<ColumnStatistic>[] cards = new List[] { lower, medium, high, 
extremelyHigh };
 
         for (NamedExpression key : context.getGroupKeys()) {
             ColumnStatistic colStats = 
ExpressionEstimation.INSTANCE.estimate(key, stats);
@@ -1287,6 +1304,21 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
             cards[groupByCardinality(colStats, 
stats.getRowCount())].add(colStats);
         }
 
+        if (!extremelyHigh.isEmpty() && context.getGroupKeys().size() > 1) {
+            return false;
+        }
+
+        if (context.isSmallBroadcastBottomJoin()) {
+            for (ColumnStatistic colStats : groupKeysStats) {
+                if (colStats.isUnKnown) {
+                    return false;
+                }
+                if (colStats.ndv * SMALL_BROADCAST_REJECT_COEFFICIENT > 
stats.getRowCount()) {
+                    return false;
+                }
+            }
+        }
+
         double lowerCartesian = 1.0;
         for (ColumnStatistic colStats : lower) {
             lowerCartesian = lowerCartesian * colStats.ndv;
@@ -1330,7 +1362,9 @@ public class EagerAggRewriter extends 
DefaultPlanRewriter<PushDownAggContext> {
     // < LOW_AGGREGATE_EFFECT_COEFFICIENT
     // lower(0): row_count / cardinality >= LOW_AGGREGATE_EFFECT_COEFFICIENT
     private int groupByCardinality(ColumnStatistic colStats, double rowCount) {
-        if (rowCount == 0 || colStats.ndv * 
MEDIUM_AGGREGATE_EFFECT_COEFFICIENT > rowCount) {
+        if (rowCount == 0 || colStats.ndv * HIGH_AGGREGATE_EFFECT_COEFFICIENT 
> rowCount) {
+            return 3;
+        } else if (colStats.ndv * MEDIUM_AGGREGATE_EFFECT_COEFFICIENT > 
rowCount) {
             return 2;
         } else if (colStats.ndv * MEDIUM_AGGREGATE_EFFECT_COEFFICIENT <= 
rowCount
                 && colStats.ndv * LOW_AGGREGATE_EFFECT_COEFFICIENT > rowCount) 
{
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggContext.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggContext.java
index 21805922634..1c72b271541 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggContext.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggContext.java
@@ -60,6 +60,7 @@ public class PushDownAggContext {
 
     private final boolean needOutputCount;
     private final boolean isPassThroughJoinOrUnion;
+    private final boolean isSmallBroadCastBottomJoin;
 
     // Bilateral push-down plumbing.
     //   - bilateralState: global, shared by every context in the rewrite 
invocation.
@@ -70,7 +71,7 @@ public class PushDownAggContext {
             boolean passThroughBigJoin, boolean hasDecomposedAggIf, boolean 
hasCaseWhen,
             BilateralState bilateralState) {
         this(aggFunctions, groupKeys, aliasMap, cascadesContext, 
passThroughBigJoin, hasDecomposedAggIf, hasCaseWhen,
-                bilateralState, false, false);
+                bilateralState, false, false, false);
     }
 
     /**
@@ -79,7 +80,8 @@ public class PushDownAggContext {
     public PushDownAggContext(List<AggregateFunction> aggFunctions,
             List<SlotReference> groupKeys, Map<AggregateFunction, Alias> 
aliasMap, CascadesContext cascadesContext,
             boolean passThroughBigJoin, boolean hasDecomposedAggIf, boolean 
hasCaseWhen,
-            BilateralState bilateralState, boolean needOutputCount, boolean 
isPassThroughJoinOrUnion) {
+            BilateralState bilateralState, boolean needOutputCount, boolean 
isPassThroughJoinOrUnion,
+            boolean isSmallBroadCastBottomJoin) {
         this.groupKeys = 
groupKeys.stream().distinct().collect(Collectors.toList());
         this.aggFunctions = ImmutableList.copyOf(aggFunctions);
         this.cascadesContext = cascadesContext;
@@ -116,6 +118,11 @@ public class PushDownAggContext {
             hintAction.ifPresent(action -> bilateralState.putAction(id, 
action));
         }
         this.isPassThroughJoinOrUnion = isPassThroughJoinOrUnion;
+        this.isSmallBroadCastBottomJoin = isSmallBroadCastBottomJoin;
+    }
+
+    public boolean isSmallBroadcastBottomJoin() {
+        return isSmallBroadCastBottomJoin;
     }
 
     public boolean isPassThroughJoinOrUnion() {
@@ -149,7 +156,7 @@ public class PushDownAggContext {
     public PushDownAggContext withGroupKeys(List<SlotReference> groupKeys) {
         return new PushDownAggContext(aggFunctions, groupKeys, aliasMap,
                 cascadesContext, passThroughBigJoin, hasDecomposedAggIf, 
hasCaseWhen,
-                bilateralState, needOutputCount, passThroughBigJoin);
+                bilateralState, needOutputCount, passThroughBigJoin, 
isSmallBroadCastBottomJoin);
     }
 
     /**
@@ -157,13 +164,13 @@ public class PushDownAggContext {
      */
     public PushDownAggContext forOneBranch(List<AggregateFunction> 
branchAggFunctions,
             Map<AggregateFunction, Alias> branchAliasMap, List<SlotReference> 
groupKeys,
-            boolean passThroughBigJoin, boolean needOutputCount) {
+            boolean passThroughBigJoin, boolean needOutputCount, boolean 
isSmallBroadcastBottomJoin) {
         if (branchAggFunctions.isEmpty() && groupKeys.isEmpty()) {
             return null;
         }
         return new PushDownAggContext(branchAggFunctions, groupKeys, 
branchAliasMap,
                 cascadesContext, passThroughBigJoin, hasDecomposedAggIf, 
hasCaseWhen,
-                bilateralState, needOutputCount, true);
+                bilateralState, needOutputCount, true, 
isSmallBroadcastBottomJoin);
     }
 
     public BilateralState getBilateralState() {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggregation.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggregation.java
index ef75f37a18f..124ef61dc8b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggregation.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/eageraggregation/PushDownAggregation.java
@@ -38,6 +38,7 @@ import 
org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
 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.trees.plans.logical.LogicalIntersect;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
 import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
@@ -76,6 +77,8 @@ public class PushDownAggregation extends 
DefaultPlanRewriter<JobContext> impleme
             Min.class);
 
     private final Set<Class> acceptNodeType = Sets.newHashSet(
+            LogicalIntersect.class,
+            LogicalAggregate.class,
             LogicalUnion.class,
             LogicalProject.class,
             LogicalFilter.class,
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 6d6ade4995c..1d025906786 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
@@ -476,7 +476,7 @@ class EagerAggRewriterTest extends TestWithFeService 
implements MemoPatternMatch
             PushDownAggContext context = new PushDownAggContext(
                     Collections.emptyList(), Collections.emptyList(), 
Collections.emptyMap(),
                     planChecker.getCascadesContext(),
-                    true, false, false, new BilateralState(), false, true);
+                    true, false, false, new BilateralState(), false, true, 
false);
 
             Plan rewritten = relation.accept(new EagerAggRewriter(), context);
 
@@ -640,7 +640,7 @@ class EagerAggRewriterTest extends TestWithFeService 
implements MemoPatternMatch
         CascadesContext cascadesContext = 
PlanChecker.from(connectContext).analyze("select * from t1")
                 .getCascadesContext();
         PushDownAggContext context = new 
PushDownAggContext(Collections.emptyList(), Collections.emptyList(),
-                Collections.emptyMap(), cascadesContext, true, false, false, 
new BilateralState(), true, false);
+                Collections.emptyMap(), cascadesContext, true, false, false, 
new BilateralState(), true, false, false);
         SlotReference leftCountSlot = new SlotReference("leftCnt", 
BigIntType.INSTANCE, false);
         SlotReference rightCountSlot = new SlotReference("rightCnt", 
BigIntType.INSTANCE, false);
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to