@@ -24,6 +24,7 @@ use datafusion_common::error::Result;
2424use datafusion_physical_plan:: aggregates:: {
2525 AggregateExec , AggregateMode , PhysicalGroupBy ,
2626} ;
27+ use datafusion_physical_plan:: coalesce_partitions:: CoalescePartitionsExec ;
2728use datafusion_physical_plan:: ExecutionPlan ;
2829
2930use crate :: PhysicalOptimizerRule ;
@@ -85,7 +86,10 @@ impl PhysicalOptimizerRule for CombinePartialFinalAggregate {
8586 input_agg_exec. aggr_expr ( ) ,
8687 input_agg_exec. filter_expr ( ) ,
8788 ) ,
88- ) {
89+ )
90+ // Don't combine if input has multiple partitions - preserve distributed aggregation
91+ && !has_multi_partition_coalesce ( input_agg_exec. input ( ) )
92+ {
8993 let mode = if agg_exec. mode ( ) == & AggregateMode :: Final {
9094 AggregateMode :: Single
9195 } else {
@@ -161,4 +165,28 @@ fn can_combine(final_agg: GroupExprsRef, partial_agg: GroupExprsRef) -> bool {
161165 )
162166}
163167
168+ /// Check if the plan subtree contains a CoalescePartitionsExec with multiple input partitions.
169+ fn has_multi_partition_coalesce ( plan : & Arc < dyn ExecutionPlan > ) -> bool {
170+ // Check if this node is CoalescePartitionsExec with multiple inputs
171+ if plan. as_any ( ) . is :: < CoalescePartitionsExec > ( ) {
172+ let partition_count = plan
173+ . children ( )
174+ . first ( )
175+ . map ( |child| child. properties ( ) . partitioning . partition_count ( ) )
176+ . unwrap_or ( 0 ) ;
177+ if partition_count > 1 {
178+ return true ;
179+ }
180+ }
181+
182+ // Recursively check all children
183+ for child in plan. children ( ) {
184+ if has_multi_partition_coalesce ( child) {
185+ return true ;
186+ }
187+ }
188+
189+ false
190+ }
191+
164192// See tests in datafusion/core/tests/physical_optimizer
0 commit comments