morningman opened a new pull request, #70177:
URL: https://github.com/apache/doris/pull/70177

   ### What problem does this PR solve?
   
   Issue Number: None
   
   Related PR: #66216, #66222, #63766
   
   Problem Summary:
   
   **In short.** This brings the FE local shuffle planner in line with 
`enable_local_exchange_before_streaming_agg`, which branch-4.1 / 4.2 #66216 and 
master #66222 added on the BE side only. With the FE planner, which master uses 
by default, a streaming pre-aggregation still asked for a local hash exchange 
on its grouping keys whatever the variable said. Master plans therefore had a 
`LOCAL_EXECUTION_HASH_SHUFFLE` local exchange that the BE planner, and 
branch-4.x, do not add, for example right above a `UNION ALL` or an external 
table scan. The FE now follows the same rule as BE `StreamingAggOperatorX`.
   
   **Background.** #66222 added `enable_local_exchange_before_streaming_agg` 
(default false) so that a streaming pre-aggregation keeps the distribution it 
inherits. It replaced `enable_local_exchange_before_agg` for streaming 
aggregation. In `StreamingAggOperatorX::required_data_distribution()`, the 
operator asks for a hash local exchange on its partition expressions only when 
the variable is on, or when 
`OperatorBase::child_breaks_local_key_distribution()` (#63766) says the child 
spreads rows without regard to any key: the child is serial, or the child's own 
required distribution is a non-hash local exchange (PASSTHROUGH, 
ADAPTIVE_PASSTHROUGH, ...).
   
   **The problem, and what it cost.** On master the FE plans local exchanges 
(`enable_local_shuffle_planner`, default true) and BE does not. 
`AggregationNode.enforceAndDeriveLocalExchange()` mirrors the BE operators, but 
its streaming aggregation branch still had the rule from before #66222. It 
never read the new variable. It skipped the hash requirement only when 
`enable_local_exchange_before_agg` was off, and then without the child check. 
With the default settings it required a hash distribution for every streaming 
pre-aggregation with grouping keys, so:
   
   - Below a streaming pre-aggregation whose child keeps the key distribution 
but does not report a hash distribution, the FE inserted a 
`LOCAL_EXECUTION_HASH_SHUFFLE` that BE planning does not. Examples are a `UNION 
ALL` and an external table scan that is not serial. Every row was hashed and 
moved once more before the pre-aggregation.
   - `enable_local_exchange_before_streaming_agg=true` had no effect with the 
FE planner.
   - With `enable_local_exchange_before_agg=false`, the FE dropped the hash 
requirement even after a child that breaks the key distribution, where BE keeps 
it.
   
   None of this changes query results: a streaming pre-aggregation only affects 
performance, and the operators that need hash-distributed input for correctness 
ask for it themselves.
   
   **How this PR fixes it.** The streaming aggregation branch of 
`AggregationNode.enforceAndDeriveLocalExchange()` now follows BE: after the 
existing hash join passthrough rule, it keeps the base class requirement (no 
exchange, or PASSTHROUGH over a serial child) unless 
`enable_local_exchange_before_streaming_agg` is on or the child breaks the key 
distribution. `enable_local_exchange_before_agg` no longer affects streaming 
aggregation. The new `childBreaksLocalKeyDistribution()` mirrors 
`child_breaks_local_key_distribution()` with each BE operator's 
`required_data_distribution()`:
   
   | Child | BE operator's required distribution | Breaks the key distribution |
   |---|---|---|
   | serial on BE (pooling scan, serial exchange, ...) | — | yes |
   | nested loop join | ADAPTIVE_PASSTHROUGH, NOOP for null-aware anti, right 
outer / semi / anti and full outer joins | yes, except those joins |
   | broadcast hash join | PASSTHROUGH when forced 
(`enable_broadcast_join_force_passthrough`) or when the probe child is serial | 
in those two cases |
   | table function, assert num rows | PASSTHROUGH | yes |
   | anything else (scan, exchange, union, partitioned join, ...) | NOOP or a 
hash distribution | no |
   
   `SelectNode` and `RepeatNode` take the serial flag of their child, so the 
serial check already covers the base class rule (PASSTHROUGH over a serial 
child) for them.
   
   **Results.** Local exchanges in the plans of three queries on a one-BE 
cluster, `parallel_pipeline_task_num=4`, non-pooling scans, taken from the 
query profiles:
   
   | Query | BE planner | FE planner before | FE planner after |
   |---|---|---|---|
   | `GROUP BY` over `UNION ALL` of two tables | none | LOCAL_HASH_SHUFFLE | 
none |
   | `GROUP BY` over a nested loop join | ADAPTIVE_PASSTHROUGH, 
LOCAL_HASH_SHUFFLE | same | same |
   | `GROUP BY` over an Iceberg table with 6 data files | none | 
LOCAL_HASH_SHUFFLE | none |
   
   A planner probe over 72 plans (8 query shapes × pooling / non-pooling scans 
× `agg_phase` 0 / 2 × the variable off / on) found only the `UNION ALL` plans 
changed with the variable off. A scan of an OLAP table, a nested loop join, 
`explode`, broadcast and shuffle joins, a `LIMIT` subquery and `GROUPING SETS` 
gave the same plans as before.
   
   ### Release note
   
   With the FE local shuffle planner (the default), a streaming pre-aggregation 
no longer adds a local hash exchange on its grouping keys above a child that 
keeps the key distribution, such as a UNION ALL or an external table scan. This 
matches the BE planner and branch-4.x. Set 
`enable_local_exchange_before_streaming_agg=true` to add the exchange.
   
   ### Check List (For Author)
   
   - Test <!-- At least one of them must be included. -->
       - [x] Regression test
       - [x] Unit Test
       - [x] Manual test (add detailed scripts or steps below)
       - [ ] No need to test or manual test. Explain why:
           - [ ] This is a refactor/code format and no logic has been changed.
           - [ ] Previous test can cover this change.
           - [ ] No code files have been changed.
           - [ ] Other reason <!-- Add your reason?  -->
   
       New tests: 4 in `LocalShuffleNodeCoverageTest` (3 fail without the fix; 
the fourth pins the child check), 2 in `LocalExchangePlannerTest` (1 fails 
without the fix), and `testSetOperationUnderAggHasHashShuffle` now turns the 
variable on. The 9 FE test classes that plan local exchanges or print 
distributed plans pass (141 tests). Each of 6 mutations of the new code fails 
only the tests aimed at it: dropping the serial check, the nested loop join 
case, the hash join case, the table function / assert num rows case, or the 
nested loop join's exception for the serial joins, or ignoring the variable. 
The new regression 
`nereids_p0/local_shuffle/test_local_exchange_before_streaming_agg` passes on a 
local one-BE cluster, and its first plan check fails on the FE without this 
fix. The profile comparison in Results was taken on the same cluster.
   
   - Behavior changed:
       - [ ] No.
       - [x] Yes. <!-- Explain the behavior change -->
   
       With the FE local shuffle planner, a streaming pre-aggregation follows 
`enable_local_exchange_before_streaming_agg` as described above, and 
`enable_local_exchange_before_agg` no longer affects it. Plans change, results 
do not.
   
   - Does this need documentation?
       - [x] No.
       - [ ] Yes. <!-- Add document PR link here. eg: 
https://github.com/apache/doris-website/pull/1214 -->
   
   ### Check List (For Reviewer who merge this PR)
   
   - [ ] Confirm the release note
   - [ ] Confirm test cases
   - [ ] Confirm document
   - [ ] Add branch pick label <!-- Add branch pick label that this PR should 
merge into -->
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to