Uh oh!
There was an error while loading. Please reload this page.
Benchmark multi-column GROUP BY performance - #22322
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…g overhead, exact NDV Addresses all three review comments from @kosiew: 1. **Implementation comparison**: Benchmarks both GroupValuesColumn (vectorized, via Int32 columns) and GroupValuesRows (row-based, via FixedSizeBinary(4) columns that trigger the fallback path) side-by-side. 2. **Execution-only timing**: Pre-optimizes the logical plan once via `df.into_parts()`. Each benchmark iteration only does physical planning + execution, excluding SQL parsing and logical optimization. 3. **Exact cardinality**: Replaces random sampling with sequential enumeration (`global_row % num_distinct_groups` decomposed per-column), guaranteeing precise distinct group counts with no birthday-paradox error. Additionally motivated by apache#17850, adds comprehensive experiments: - Issue apache#17850 regression reproduction (3 cols, 64 groups, 1M-50M rows) - Low cardinality sweep (8-4096 groups) - Batch size sensitivity (1K-32K) - Column count scaling (2-10 cols, low and high cardinality) - Group count sweep (16 to 1M groups) - Random vs sequential data patterns Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a fair apples-to-apples benchmark that directly calls GroupValues::intern() with identical Int32 data for both GroupValuesColumn (vectorized) and GroupValuesRows (row-based). This eliminates the previous confounding factors (different data types, SQL/planning overhead) and confirms the regression reported in apache#17850: row-based is 16-19% faster at low cardinality (64 groups), with a crossover at ~200K-500K groups where vectorized becomes faster. Experiments: - Issue apache#17850 reproduction (3 cols, 64 groups, 1M-50M rows) - Low cardinality sweep (8-4096 groups) - Batch size sensitivity (1K-32K) - Column count scaling (2-10 cols) - High cardinality scaling (1M groups) - Group count sweep (16 to 1M groups) - Random vs sequential data patterns
Uh oh!
There was an error while loading. Please reload this page.
nathanb9
commented
May 20, 2026
Thanks for the review @kosiew. Changes from your comments:
One thing im not sure about: making |
There was a problem hiding this comment.
@nathanb9
Thanks for the updates here. The benchmark changes address the earlier concerns around comparing GroupValuesColumn vs GroupValuesRows directly and removing SQL planning overhead from the measured path.
I still found one issue with the 1M-group benchmark cases. Because generate_batches truncates to whole batches, the generated input for the advertised 1_000_000 row/group cases is actually smaller than the benchmark labels suggest.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@kosiew Thanks for your thorough review |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Adds `GroupValuesFlatPrimitive`, a direct-indexing GroupValues implementation for integer-typed GROUP BY columns with bounded value ranges. Uses `value - min` to index directly into a flat array — no hashing, no collisions, O(1) lookup. Adds a benchmark (`single_group_by_primitive`) that directly compares hash-based `GroupValuesPrimitive` vs `GroupValuesFlatPrimitive` using the same `iter_batched_ref` methodology as the multi-column GROUP BY benchmark in apache#22322. Only `intern()` is timed; construction is in setup. Three experiments: 1. Group count sweep (10–100K groups, 1M rows) 2. Density sweep (10K groups, 10%–100% density) 3. Row count scaling (10K groups, 1M–10M rows) Closes benchmarking aspect of apache#19938. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Which issue does this PR close?
Rationale for this change
GroupValuesColumn) underperforms the row-based approach (GroupValuesRows) when distinct group count is small relativeto input rows. The benchmark confirms this: row-based is 16-19% faster below ~200K groups, while vectorized wins by 15-33% above ~500K groups.
What changes are included in this PR?
Adds a benchmark in
datafusion/physical-plan/benches/multi_group_by.rsthat directly callsGroupValues::intern()with identical Int32 data for both implementations —no SQL/planning/IO overhead, same schema, same hashing.
Makes
mod rowpublic so the benchmark can instantiateGroupValuesRowsdirectly.Test cases:
Are these changes tested?
cargo fmt --allcargo clippy -p datafusion-physical-plan --bench multi_group_by -- -D warningscargo bench -p datafusion-physical-plan --bench multi_group_byAre there any user-facing changes?
No. This adds a benchmark only.