Skip to content

Grouped aggregates get none of the vectorized aggregate work: measure first, then decide #349

Description

@jdatcmd

Successor to #289, which is closed. That issue's diagnosis came from a profile taken while column projection was silently broken (#338), and its headline claim has since been measured and contradicted: on the 100M bench, serial-to-serial, pgColumnar now runs its q6 shape in 4,357 ms against TimescaleDB's 5,597 ms. This issue covers what measurement says actually remains.

The gap, verified in code

Grouped aggregates receive none of the vectorized aggregate work that landed under #289.

ColumnarCreateUpperPaths (src/columnar_vector.c:816-829) branches on the query shape. When groupClause != NIL it either adds the grouped path or nothing, and then returns -- so #337 (serial batch fold), #343 (parallel partial agg) and #346 (int partials) are unreachable for any grouped query.

What a grouped aggregate actually gets today:

state
column projection (#339) on by default, applies (it is scan-level)
serial batch fold (#337) never reached
parallel partial agg (#343/#346) never reached
grouped vectorized node (#321) behind pgcolumnar.enable_group_vectorization, default off
that node's parallelism none -- parallel_aware = false, parallel_workers = 0 (src/columnar_vector.c:938-940), and columnar_groupagg_exec_methods declares no DSM callbacks

So a default install answers a grouped aggregate with a projected scan feeding an ordinary row-wise Agg.

This is not a niche shape. Three of the four TSBS queries in #289's own table -- q4 (group by host), q5 (10 aggregates, grouped), q8 (top 20 by max) -- are grouped.

What is deliberately NOT claimed here

Nothing about the size of this. No grouped shape has been measured on current main. The published q4/q5 figures in docs/benchmarks.md show pgColumnar losing to heap, but those predate #339 (see #348), so they say nothing about today.

That is the specific mistake #289 made -- a plan built on a profile rather than on a measurement of the thing being planned -- and it is worth not repeating in its successor.

First step: measure, then decide

Before any implementation, on the 100M bench, current main, fixtures asserted, buffers alongside times, all arms in one session:

  1. q4, q5 and q8 with projection on vs off. Establishes what the one lever that already applies is worth on grouped shapes.
  2. The same with enable_group_vectorization on vs off. Establishes whether the existing Grouped vectorized aggregate (#289) #321 node earns its keep, and whether its default-off is the right default.
  3. The same against heap and TimescaleDB serial on the same box, so the comparison is like-for-like. Note that TimescaleDB's parallel path currently faults on the bench (could not read blocks 0..0, see docs/benchmarks.md cross-engine table was measured before column projection landed and understates pgColumnar by ~50x on q6 #348), so cross-engine parallel numbers are not available until that is repaired.

Only after that should anyone choose between: making the grouped node parallel-aware, extending the batch fold to grouped shapes, or turning enable_group_vectorization on by default.

Second item, independent of the above

The batch fold pushes no scan keys, so it forfeits zone-map group pruning. ColumnarBeginRead is called with nkeys = 0 from the fold path, and with no predicates columnar_build_predicates returns immediately, so no group skipping and no vector skipping occurs.

On a randomly filled fixture this costs nothing -- no group's min/max rules out usage_user > 90.0, so nothing would have been pruned. On clustered or time-ranged data, which is the TSBS-shaped workload, enabling the fold may trade pruning for folding, and the sign of that trade is not obvious.

Detectable without any timing: under the fold, EXPLAIN reports Columnar Chunk Groups Removed by Filter: 0 regardless of how selective the predicate is. Worth confirming on a clustered fixture before it bites someone.

Third item

Three of the four levers default off (enable_ungrouped_vector_agg, enable_parallel_vector_agg, enable_group_vectorization). A default install gets projection and nothing else. Whether that is intended is a separate decision, but it should be a decision rather than an accident, and the defaults should be stated wherever performance numbers are published.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions