Skip to content

fix: do not remove DISTINCT when a unique key was downgraded by a join#23548

Open
simonvandel wants to merge 2 commits into
apache:mainfrom
simonvandel:push-omqkkpttorsz
Open

fix: do not remove DISTINCT when a unique key was downgraded by a join#23548
simonvandel wants to merge 2 commits into
apache:mainfrom
simonvandel:push-omqkkpttorsz

Conversation

@simonvandel

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

  • Closes #.

Rationale for this change

The ReplaceDistinctWithAggregate optimization pass was incorrectly removing deduplication.

What changes are included in this PR?

First commit reproduces the bug in an SLT. I opted for SLT instead of a test inside datafusion/optimizer/src/replace_distinct_aggregate.rs since SLT seems easier to maintain. But let me know if you prefer the test elsewhere.

Second commit fixes the bug. Also includes a drive-by documentation change for Dependency to surface the field docs.

Are these changes tested?

Yes

Are there any user-facing changes?

Yes, query now deduplicates correctly

…a join

`ReplaceDistinctWithAggregate` removes `Distinct::All` when a functional
dependence covers all input fields, but it ignores the dependency mode:
after a join a formerly-unique key is downgraded to `Dependency::Multi`,
so the input may still contain duplicates. This SLT test records the
current wrong behavior: `SELECT DISTINCT u.id` over a LEFT JOIN returns
one row per matching order instead of one row per user.
`ReplaceDistinctWithAggregate` removes `Distinct::All` when a functional
dependence's determinant columns cover all input fields, treating the
input as already deduplicated. However it ignored the dependency mode:
after a join, `FunctionalDependencies::join` downgrades dependencies to
`Dependency::Multi` because a formerly-unique key may now occur in many
rows. Removing the DISTINCT in that case returns duplicate rows.

For example, with `users.id` as a primary key and several orders per
user:

    SELECT DISTINCT users.id FROM users LEFT JOIN orders ON users.id = orders.user_id

returned `id` values repeated once per matching order.

Only remove the DISTINCT when the dependency mode is `Single`, i.e. the
determinant key is guaranteed to occur at most once. The sqllogictest
added in the previous commit now shows the correct deduplicated result
and an Aggregate in the plan.
@github-actions github-actions Bot added optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt) common Related to common crate labels Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

common Related to common crate optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant