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

   ## Problem
   
   With the FE local-shuffle planner enabled (default 
`enable_local_shuffle_planner=true`), a scalar `COUNT(DISTINCT k)` over joins 
can return a wrong result that grows linearly with `parallel_pipeline_task_num` 
(e.g. expected 10, got 30 with 3 tasks).
   
   The bad plan shape:
   
   ```
   VAGGREGATE (merge finalize)  output: sum0(multi_distinct_count(k))   -- sums 
per-instance values
   VAGGREGATE (merge finalize)  output: multi_distinct_count(k)         -- no 
group keys
   VHASH JOIN (LEFT OUTER BROADCAST)
     VLOCAL-EXCHANGE (PASSTHROUGH)                                      -- 
scatters hash-partitioned rows
   VHASH JOIN (RIGHT OUTER PARTITIONED)  output: hash-partitioned by k  -- 
key-aligned here
   ```
   
   `AggregationNode.enforceAndDeriveLocalExchange` gave a **NoRequire** 
distribution to a finalize merge agg with no group keys, treating it like 
`COUNT(*)`. Unlike `COUNT(*)`, a `multi_distinct_count` finalize agg emits 
per-instance **scalar values** that the parent `sum0` adds up — correctness 
requires the input to be hash-partitioned by the distinct key. When a 
PASSTHROUGH local exchange (broadcast-join probe fan-out) scatters same-key 
rows across instances, the parent double-counts overlapping keys. The result 
equals `correct × local task count`.
   
   The BE-native path was already protected 
(`AggSinkOperatorX::required_data_distribution` checks `_partition_exprs`, and 
`child_breaks_local_key_distribution` from a prior fix), so 
`enable_local_shuffle_planner=false` was unaffected — only the FE-planned path 
was wrong.
   
   ## Root cause
   
   The FE planner used `hasKeys` (grouping exprs empty?) as the 
partition-requirement test, but BE's `_partition_exprs` is non-empty whenever 
the agg has group keys **or DISTINCT aggregates** (`distribute_expr_lists` + 
`has_distinct`). The FE fell back to NoRequire for the distinct case, skipping 
the hash local exchange that the agg needs.
   
   ## Changes
   
   - `AggregationNode` now mirrors BE's `_partition_exprs` semantics via 
`hasPartitionRequirement()` (grouping exprs or `multi_distinct_*` functions): a 
finalize agg with a partition requirement demands HASH from its child; only 
partition-less aggs (`COUNT(*)`-style) keep NoRequire.
   - The finalize branch that previously trusted the child's distribution now 
requires HASH explicitly — when the child already provides hash distribution 
the `satisfy()` check passes and no LE is inserted, so the common case is 
unchanged and free.
   - `requiresShuffleForCorrectness()` now covers DISTINCT aggregates to match 
BE's `is_shuffled_operator()`.
   
   ## Tests
   
   - `LocalShuffleNodeCoverageTest`: unit coverage for `AggregationNode` across 
finalize/LOCAL/FIRST_MERGE phases × distinct/no-distinct × 
`enable_local_exchange_before_agg` on/off, plus `requiresShuffleForCorrectness` 
cases. Pre-fix the distinct-finalize case asserted NoRequire; post-fix it 
asserts RequireHash.
   - `LocalExchangePlannerTest`: sql-level distributed-plan test — the 
RQG-shaped query (`count(distinct)` over a shuffle join + a broadcast join with 
probe forced to PASSTHROUGH) must contain a `LOCAL_EXECUTION_HASH_SHUFFLE` 
local exchange below the distinct finalize agg. Verified this test fails 
without the fix (plan only has `PASSTHROUGH`) and passes with it.
   - End-to-end on a 3-BE cluster with the RQG dataset: expected 10; the 
pre-fix behavior (30, scaling with `parallel_pipeline_task_num`) now returns 10 
under all session-var combinations, including 
`parallel_pipeline_task_num=1/2/4/6`.
   


-- 
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