gmhelmold opened a new pull request, #23486:
URL: https://github.com/apache/datafusion/pull/23486

   ## Which issue does this PR close?
   
   - Closes #23401.
   
   ## Rationale for this change
   
   `SingleDistinctToGroupBy` rewrites a grouped `AGG(DISTINCT col)` into a 
cheaper nested double aggregate. Today the rule only recognizes a **bare** 
`Expr::AggregateFunction` in `Aggregate.aggr_expr`, so it fires for plans from 
the SQL planner but silently skips the logically-identical plan built through 
the DataFrame API — that path runs materially slower for the same query.
   
   The divergence is purely in where each front-end places the output alias:
   
   - **SQL** (`count(DISTINCT v) AS n`): the planner hoists `AS n` into an 
outer `Projection`, leaving a bare `Expr::AggregateFunction` in `aggr_expr`.
   - **DataFrame API** (`count(col("v")).distinct().alias("n")`): `.alias(..)` 
wraps the aggregate directly, so `aggr_expr` holds 
`Expr::Alias(AggregateFunction)`.
   
   `is_single_distinct_agg` matched only the bare shape and returned `false` 
for `Alias(AggregateFunction)`, so the rule never fired for DataFrame-API 
distinct aggregates.
   
   ## What changes are included in this PR?
   
   - Unwrap a single `Expr::Alias` layer in the matcher 
(`is_single_distinct_agg`) and in the rewrite, mirroring the one-layer 
`unalias()` idiom already used in the optimizer (e.g. `decorrelate.rs`), so 
both front-end shapes are recognized identically.
   - The user-facing alias is preserved without extra work: the rewrite already 
rebuilds the final output `Projection` from the original `Aggregate` schema 
(`schema.qualified_field(idx)`), so `AS n` survives.
   - Bare-aggregate behavior is unchanged (byte-identical): every pre-existing 
snapshot passes untouched.
   
   ## Are these changes tested?
   
   Yes — new snapshot tests in `single_distinct_to_groupby.rs`:
   
   - `single_distinct_aliased` — the DataFrame-API `Alias(AggregateFunction)` 
shape is now rewritten, and the output column stays named `n`.
   - `single_distinct_aliased_and_groupby` — same, alongside a real `GROUP BY` 
column.
   - `non_distinct_aliased` and `two_distinct_aliased_and_groupby` — negative 
cases: an aliased non-distinct aggregate, and two aliased distinct aggregates 
on different fields, are still (correctly) left untouched.
   
   Reverting the production change makes the two positive tests fail (the rule 
no longer fires) while every other test stays green, confirming the tests are 
wired to the fix.
   
   ## Are there any user-facing changes?
   
   No API changes. DataFrame-API queries using `count(distinct …)` (and other 
single-distinct aggregates) now receive the same optimized plan as their SQL 
equivalents — a performance improvement, with no change to results or output 
column names.
   


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