Skip to content

Support GroupsAccumulator for unordered first_value #27149

Description

@rkrishn7

Is your feature request related to a problem or challenge?

first_value only provides a GroupsAccumulator when it has an ORDER BY:

fn groups_accumulator_supported(args: &AccumulatorArgs) -> bool {
    !args.order_bys.is_empty() && matches!(/* supported types */)
}

Without an ordering, grouped aggregation falls back to GroupsAccumulatorAdapter, which keeps one boxed TrivialFirstValueAccumulator per group. Each of those holds its value as a ScalarValue. Time and memory per group are therefore much higher than for the native grouped accumulators, and the gap grows with the number of groups.

Unordered first_value is common because the planner produces it: ReplaceDistinctWithAggregate rewrites SELECT DISTINCT ON (keys) cols with no ORDER BY into an aggregate grouped by keys with one first_value(col) per selected column. Any DISTINCT ON over a high-cardinality key takes this path, as does first_value(col) written without ORDER BY. (Plain SELECT DISTINCT is unaffected; it becomes a GROUP BY with no aggregates.)

On the ClickBench hits dataset, for example:

SELECT DISTINCT ON ("UserID") "UserID", "URL", "Title", "SearchPhrase", "EventTime", "RegionID"
FROM hits;

There are 17.6 million distinct UserID values. On main (b6b2e0e), on a 14-core M4 Pro with 24 GB of memory, this query takes 73 s and the process peaks at about 21 GB. A single first_value("WatchID") grouped by UserID takes 6.2 s and peaks at about 6.6 GB.

Describe the solution you'd like

A native GroupsAccumulator for first_value without ORDER BY. It needs no ordering state: a group keeps the first qualifying row it sees and is never written again. The existing ValueState implementations
(PrimitiveValueState, BytesValueState, GenericValueState) already store values per group for the ordered accumulator and can be reused.

The intermediate state should stay [first_value, is_set], the layout of TrivialFirstValueAccumulator, so partial and final aggregation see the same schema as today.

Describe alternatives you've considered

Additional context

last_value without ORDER BY has the same fallback. It could get a similar accumulator but is left out of scope here; the planner does not produce it.

Willingness to contribute

I plan to contribute to this feature independently

Activity

  1. added theissue type on Nov 6, 2026
  2. rkrishn7 commented on Nov 6, 2026

    @rkrishn7
    ContributorAuthor

    take

  3. added a commit that references this issue on Nov 7, 2026
    26de352
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions