Skip to content

fix: don't declare Unique group keys for partial aggregation output - #26819

Open
viirya wants to merge 1 commit into
apache:mainfrom
viirya:fix-partial-agg-unique-constraint
Open

viirya wants to merge 1 commit into
apache:mainfrom
viirya:fix-partial-agg-unique-constraint

Conversation

@viirya

@viirya viirya commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Which issue does this PR close?

Rationale for this change

AggregateExec declares Unique(group keys) for every aggregation mode, including Partial and PartialReduce. Partial state is not unique on the group keys. Operators that merge partitions keep the constraint, and a partial stage can also emit the same group more than once within a partition. ordering_satisfy treats [k] plus Unique(k) as satisfying [k, x], so a required sort can be dropped. For example, with prefer_existing_sort, a sort on [k, sum] above a hash repartition of a Partial aggregate is replaced by an order-preserving repartition, and rows with equal k come out unsorted.

What changes are included in this PR?

AggregateExec::compute_properties adds the Unique constraint only when the mode's output is final (Final, FinalPartitioned, Single, SinglePartitioned). Constraints projected from the input are unchanged.

Default SQL plans always put the Final aggregate above the Partial one. The Final aggregate keeps declaring Unique, and its input ordering requirement covers only the group keys, so this doesn't change any plan in the sqllogictests.

What is the testing strategy for this PR?

  • partial_aggregate_does_not_declare_unique_group_keys in physical-plan/src/aggregates/mod.rs: a Partial aggregate over two sorted partitions declares no constraint, SortExec([k, sum]) over SortPreservingMergeExec([k]) sorts the merged rows, and the Final aggregate still declares Unique.
  • test_keep_sort_above_repartitioned_partial_aggregate in core/tests/physical_optimizer/enforce_sorting.rs: with prefer_existing_sort, EnsureRequirements keeps the SortExec above the hash repartition of the Partial aggregate, and every output partition is sorted.

Both tests fail without the change.

Are there any user-facing changes?

No. Partial aggregate output no longer advertises a Unique constraint on its group keys.

Partial and PartialReduce aggregates declared Unique(group keys), but
partial state is not unique on the group keys: partition merges keep the
constraint, and a partial stage can emit a group more than once. The
stale constraint let an ordering on the group keys satisfy a longer
ordering, so a required sort could be removed (e.g. replaced by an
order-preserving repartition with prefer_existing_sort).

Only declare the constraint for modes that produce final values.

Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions github-actions Bot added core Core DataFusion crate physical-plan Changes to the physical-plan crate labels Oct 27, 2026
@viirya
viirya requested review from alamb, comphead and sunchao October 27, 2026 18:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Core DataFusion crate physical-plan Changes to the physical-plan crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Partial aggregate declares Unique on group keys, which lets a needed sort be removed

1 participant