Skip to content

fix: Only apply SingleDistinctToGroupBy rewrite when it pays (closes #25932) - #26000

Open
mohitgurav20 wants to merge 38 commits into
apache:mainfrom
mohitgurav20:fix/single-distinct-groupby-memory-usage
Open

mohitgurav20 wants to merge 38 commits into
apache:mainfrom
mohitgurav20:fix/single-distinct-groupby-memory-usage

Conversation

@mohitgurav20

@mohitgurav20 mohitgurav20 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Closes #25932.

Rationale for this change

In queries with a single distinct aggregation, SingleDistinctToGroupBy rewrites the plan into a two-phase GROUP BY. While this enables partition parallelism, it materializes intermediate (group, distinct_value) pairs, increasing peak intermediate memory (~538–599 MiB vs ~306 MiB in unconstrained memory runs).

PR #25988 previously added datafusion.optimizer.single_distinct_prefer_native specifically for COUNT(DISTINCT int). Per review feedback from @mkleen, rather than introducing a separate knob (single_distinct_aggregation_prefer_memory), this PR consolidates both behaviors into datafusion.optimizer.single_distinct_prefer_native.

At target_partitions = 1, native GroupsAccumulator execution avoids the two-phase grouping overhead and reduces peak memory for fixed-width non-floating types (such as sum(DISTINCT int) and count(DISTINCT int)). When target_partitions > 1, queries continue using the two-phase rewrite to maintain partition fan-out and support spilling under memory limits.

What changes are included in this PR?

  1. Consolidated Configuration Knob:

    • Extended datafusion.optimizer.single_distinct_prefer_native: bool (default false) to govern all native single distinct paths, dropping the separate single_distinct_aggregation_prefer_memory setting.
    • Clarified documentation in config.rs and configs.md regarding memory, partition gating, and spilling trade-offs.
  2. Opt-in Native Execution Gating:

    • When single_distinct_prefer_native = true and target_partitions == 1, skips the two-phase rewrite if all distinct aggregate arguments are fixed-width, non-floating types (integers, dates, decimals) supported by native GroupsAccumulator.
    • Excludes floating-point types (f32, f64) to preserve IEEE 754 -0.0 == 0.0 semantics (which differ between GROUP BY and raw-bit accumulator hashing).
    • Multi-partition plans (target_partitions > 1), queries with non-distinct companion aggregates, and aggregates with unsupported distinct handling (such as approx_median or stddev) continue with the two-phase rewrite.
  3. Documentation & Schema Synchronization:

    • Updated docs/source/user-guide/configs.md.
    • Updated information_schema.slt, grouped_count_distinct.slt, and single_distinct_to_groupby.slt.

Are these changes tested?

Yes:

  • Unit tests in single_distinct_to_groupby.rs covering flag states, partition gating (target_partitions == 1 vs > 1), float argument exclusions, and unsupported aggregate fallbacks.
  • Sqllogictests for plan inspection (EXPLAIN) and end-to-end query execution across single_distinct_to_groupby.slt and grouped_count_distinct.slt.
  • Verified formatting, clippy (cargo clippy --all-targets --all-features -- -D warnings), and full optimizer test suite.

Are there any user-facing changes?

Yes:

  • Extends the behavior of configuration setting datafusion.optimizer.single_distinct_prefer_native. No breaking API changes.

@github-actions github-actions Bot added the optimizer Optimizer rules label Oct 3, 2026
@mohitgurav20
mohitgurav20 force-pushed the fix/single-distinct-groupby-memory-usage branch from 527a544 to 9e8dfe6 Compare October 4, 2026 16:36
@github-actions github-actions Bot added the core Core DataFusion crate label Oct 4, 2026

@mkleen mkleen left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mohitgurav20 Thanks for working on this.
Can you make sure all sql-logic tests pass, or correct them if invalid.
You can run them locally with:

cargo test --profile=ci --test sqllogictests

@github-actions github-actions Bot added the sqllogictest SQL Logic Tests (.slt) label Oct 9, 2026
@codecov-commenter

codecov-commenter commented Oct 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.53541% with 44 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.94%. Comparing base (3ee3e39) to head (38468c5).
⚠️ Report is 29 commits behind head on main.

Files with missing lines Patch % Lines
...fusion/optimizer/src/single_distinct_to_groupby.rs 87.50% 3 Missing and 41 partials ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main   #26000    +/-   ##
========================================
  Coverage   82.93%   82.94%            
========================================
  Files        1154     1154            
  Lines      458002   458300   +298     
  Branches   458002   458300   +298     
========================================
+ Hits       379856   380130   +274     
+ Misses      55123    55104    -19     
- Partials    23023    23066    +43     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mohitgurav20
mohitgurav20 force-pushed the fix/single-distinct-groupby-memory-usage branch from 63e9873 to 0c76607 Compare October 10, 2026 19:06
@mohitgurav20
mohitgurav20 requested a review from mkleen October 11, 2026 05:11
@mohitgurav20

Copy link
Copy Markdown
Contributor Author

@mkleen sir i have completed the work and addressed ur suggestion pls feel free to review and would like to work if any changes needed.

@mkleen

mkleen commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

run benchmarks

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c6114216591-3306-6nkh2 6.12.94+ #1 SMP Fri Aug 21 08:00:16 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing fix/single-distinct-groupby-memory-usage (0923424) to 334f293 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c6114216591-3307-dzrvx 6.12.94+ #1 SMP Fri Aug 21 08:00:16 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing fix/single-distinct-groupby-memory-usage (0923424) to 334f293 (merge-base) diff

Run configuration
run benchmark tpcds

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c6114216591-3308-fcbjc 6.12.94+ #1 SMP Fri Aug 21 08:00:16 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing fix/single-distinct-groupby-memory-usage (0923424) to 334f293 (merge-base) diff

Run configuration
run benchmark tpch

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing fix/single-distinct-groupby-memory-usage (0923424) to 334f293 (merge-base) diff

Run configuration
run benchmark tpch
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃     HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │ 40.29 ms │                                 40.32 ms │     no change │
│ QQuery 2  │ 18.13 ms │                                 18.16 ms │     no change │
│ QQuery 3  │ 28.23 ms │                                 28.28 ms │     no change │
│ QQuery 4  │ 17.14 ms │                                 17.06 ms │     no change │
│ QQuery 5  │ 35.12 ms │                                 35.57 ms │     no change │
│ QQuery 6  │ 13.35 ms │                                 13.56 ms │     no change │
│ QQuery 7  │ 42.15 ms │                                 41.29 ms │     no change │
│ QQuery 8  │ 40.83 ms │                                 41.29 ms │     no change │
│ QQuery 9  │ 50.50 ms │                                 50.92 ms │     no change │
│ QQuery 10 │ 40.28 ms │                                 40.46 ms │     no change │
│ QQuery 11 │ 13.26 ms │                                 13.27 ms │     no change │
│ QQuery 12 │ 18.03 ms │                                 18.43 ms │     no change │
│ QQuery 13 │ 39.16 ms │                                 38.90 ms │     no change │
│ QQuery 14 │ 24.47 ms │                                 24.44 ms │     no change │
│ QQuery 15 │ 30.29 ms │                                 30.73 ms │     no change │
│ QQuery 16 │ 13.63 ms │                                 11.66 ms │ +1.17x faster │
│ QQuery 17 │ 73.99 ms │                                 73.56 ms │     no change │
│ QQuery 18 │ 45.29 ms │                                 45.11 ms │     no change │
│ QQuery 19 │ 31.51 ms │                                 31.65 ms │     no change │
│ QQuery 20 │ 31.36 ms │                                 31.67 ms │     no change │
│ QQuery 21 │ 54.39 ms │                                 54.99 ms │     no change │
│ QQuery 22 │ 13.54 ms │                                 13.63 ms │     no change │
└───────────┴──────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 714.94ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 714.93ms │
│ Average Time (HEAD)                                     │  32.50ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │  32.50ms │
│ Queries Faster                                          │        1 │
│ Queries Slower                                          │        0 │
│ Queries with No Change                                  │       21 │
│ Queries with Failure                                    │        0 │
└─────────────────────────────────────────────────────────┴──────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                           HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │ 40.29 / 40.97 ±1.06 / 43.07 ms │           40.32 / 41.00 ±0.96 / 42.90 ms │     no change │
│ QQuery 2  │ 18.13 / 18.38 ±0.33 / 18.98 ms │           18.16 / 18.50 ±0.29 / 18.98 ms │     no change │
│ QQuery 3  │ 28.23 / 28.63 ±0.30 / 29.12 ms │           28.28 / 28.61 ±0.23 / 28.91 ms │     no change │
│ QQuery 4  │ 17.14 / 17.56 ±0.60 / 18.74 ms │           17.06 / 17.30 ±0.19 / 17.62 ms │     no change │
│ QQuery 5  │ 35.12 / 36.10 ±1.42 / 38.90 ms │           35.57 / 35.67 ±0.07 / 35.80 ms │     no change │
│ QQuery 6  │ 13.35 / 13.81 ±0.56 / 14.90 ms │           13.56 / 14.42 ±0.87 / 15.93 ms │     no change │
│ QQuery 7  │ 42.15 / 42.74 ±0.69 / 43.78 ms │           41.29 / 43.01 ±1.29 / 44.83 ms │     no change │
│ QQuery 8  │ 40.83 / 42.21 ±2.10 / 46.38 ms │           41.29 / 42.71 ±2.33 / 47.35 ms │     no change │
│ QQuery 9  │ 50.50 / 51.06 ±0.54 / 51.88 ms │           50.92 / 51.07 ±0.17 / 51.38 ms │     no change │
│ QQuery 10 │ 40.28 / 42.76 ±3.92 / 50.57 ms │           40.46 / 40.79 ±0.21 / 41.11 ms │     no change │
│ QQuery 11 │ 13.26 / 13.65 ±0.36 / 14.27 ms │           13.27 / 13.77 ±0.65 / 15.05 ms │     no change │
│ QQuery 12 │ 18.03 / 18.38 ±0.34 / 19.02 ms │           18.43 / 18.66 ±0.17 / 18.90 ms │     no change │
│ QQuery 13 │ 39.16 / 39.35 ±0.10 / 39.43 ms │           38.90 / 39.73 ±1.25 / 42.18 ms │     no change │
│ QQuery 14 │ 24.47 / 24.61 ±0.08 / 24.69 ms │           24.44 / 24.54 ±0.09 / 24.69 ms │     no change │
│ QQuery 15 │ 30.29 / 30.71 ±0.32 / 31.22 ms │           30.73 / 31.08 ±0.35 / 31.72 ms │     no change │
│ QQuery 16 │ 13.63 / 13.87 ±0.15 / 14.10 ms │           11.66 / 12.02 ±0.22 / 12.31 ms │ +1.15x faster │
│ QQuery 17 │ 73.99 / 74.37 ±0.23 / 74.61 ms │           73.56 / 74.20 ±0.38 / 74.60 ms │     no change │
│ QQuery 18 │ 45.29 / 45.54 ±0.21 / 45.89 ms │           45.11 / 46.05 ±0.96 / 47.78 ms │     no change │
│ QQuery 19 │ 31.51 / 31.91 ±0.34 / 32.51 ms │           31.65 / 33.01 ±1.31 / 35.23 ms │     no change │
│ QQuery 20 │ 31.36 / 31.78 ±0.46 / 32.62 ms │           31.67 / 31.92 ±0.26 / 32.39 ms │     no change │
│ QQuery 21 │ 54.39 / 55.74 ±1.66 / 58.89 ms │           54.99 / 56.49 ±0.98 / 57.55 ms │     no change │
│ QQuery 22 │ 13.54 / 13.71 ±0.13 / 13.91 ms │           13.63 / 13.91 ±0.22 / 14.16 ms │     no change │
└───────────┴────────────────────────────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 727.85ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 728.44ms │
│ Average Time (HEAD)                                     │  33.08ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │  33.11ms │
│ Queries Faster                                          │        1 │
│ Queries Slower                                          │        0 │
│ Queries with No Change                                  │       21 │
│ Queries with Failure                                    │        0 │
└─────────────────────────────────────────────────────────┴──────────┘

Resource Usage

tpch — base (merge-base)

Metric Value
Wall time 5.0s
Peak memory 1.1 GiB
Avg memory 473.9 MiB
CPU user 19.8s
CPU sys 1.7s
Peak spill 0 B

tpch — branch

Metric Value
Wall time 5.0s
Peak memory 1.1 GiB
Avg memory 478.5 MiB
CPU user 19.9s
CPU sys 1.6s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing fix/single-distinct-groupby-memory-usage (0923424) to 334f293 (merge-base) diff

Run configuration
run benchmark tpcds
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │    5.42 ms │                                  5.48 ms │     no change │
│ QQuery 2  │   79.52 ms │                                 79.63 ms │     no change │
│ QQuery 3  │   28.07 ms │                                 28.11 ms │     no change │
│ QQuery 4  │  428.64 ms │                                427.69 ms │     no change │
│ QQuery 5  │   49.27 ms │                                 49.56 ms │     no change │
│ QQuery 6  │   34.13 ms │                                 34.40 ms │     no change │
│ QQuery 7  │   71.83 ms │                                 71.95 ms │     no change │
│ QQuery 8  │   35.53 ms │                                 35.81 ms │     no change │
│ QQuery 9  │   50.74 ms │                                 50.77 ms │     no change │
│ QQuery 10 │   61.74 ms │                                 61.42 ms │     no change │
│ QQuery 11 │  261.04 ms │                                264.22 ms │     no change │
│ QQuery 12 │   28.34 ms │                                 28.31 ms │     no change │
│ QQuery 13 │  111.88 ms │                                111.92 ms │     no change │
│ QQuery 14 │  382.80 ms │                                380.70 ms │     no change │
│ QQuery 15 │   51.27 ms │                                 52.04 ms │     no change │
│ QQuery 16 │    6.20 ms │                                  5.51 ms │ +1.12x faster │
│ QQuery 17 │   78.98 ms │                                 77.83 ms │     no change │
│ QQuery 18 │  102.77 ms │                                103.49 ms │     no change │
│ QQuery 19 │   40.90 ms │                                 40.78 ms │     no change │
│ QQuery 20 │   35.30 ms │                                 35.07 ms │     no change │
│ QQuery 21 │   16.52 ms │                                 16.40 ms │     no change │
│ QQuery 22 │   62.15 ms │                                 62.80 ms │     no change │
│ QQuery 23 │  299.29 ms │                                299.83 ms │     no change │
│ QQuery 24 │  189.60 ms │                                189.43 ms │     no change │
│ QQuery 25 │  107.82 ms │                                106.95 ms │     no change │
│ QQuery 26 │   45.49 ms │                                 45.27 ms │     no change │
│ QQuery 27 │    5.79 ms │                                  5.81 ms │     no change │
│ QQuery 28 │   55.00 ms │                                 60.08 ms │  1.09x slower │
│ QQuery 29 │   94.14 ms │                                 95.50 ms │     no change │
│ QQuery 30 │   32.64 ms │                                 31.94 ms │     no change │
│ QQuery 31 │  105.84 ms │                                107.09 ms │     no change │
│ QQuery 32 │   20.02 ms │                                 19.43 ms │     no change │
│ QQuery 33 │   35.91 ms │                                 36.15 ms │     no change │
│ QQuery 34 │    9.69 ms │                                  9.76 ms │     no change │
│ QQuery 35 │   70.62 ms │                                 70.50 ms │     no change │
│ QQuery 36 │    5.51 ms │                                  5.43 ms │     no change │
│ QQuery 37 │    6.57 ms │                                  6.52 ms │     no change │
│ QQuery 38 │   60.02 ms │                                 59.40 ms │     no change │
│ QQuery 39 │   71.53 ms │                                 71.64 ms │     no change │
│ QQuery 40 │   23.38 ms │                                 22.17 ms │ +1.05x faster │
│ QQuery 41 │   10.97 ms │                                 11.04 ms │     no change │
│ QQuery 42 │   22.91 ms │                                 22.91 ms │     no change │
│ QQuery 43 │    4.63 ms │                                  4.69 ms │     no change │
│ QQuery 44 │    8.50 ms │                                  8.59 ms │     no change │
│ QQuery 45 │   35.60 ms │                                 35.13 ms │     no change │
│ QQuery 46 │   11.45 ms │                                 11.43 ms │     no change │
│ QQuery 47 │  214.57 ms │                                215.34 ms │     no change │
│ QQuery 48 │   90.01 ms │                                 89.35 ms │     no change │
│ QQuery 49 │   68.33 ms │                                 68.31 ms │     no change │
│ QQuery 50 │   58.02 ms │                                 57.54 ms │     no change │
│ QQuery 51 │   92.75 ms │                                 91.56 ms │     no change │
│ QQuery 52 │   23.21 ms │                                 23.49 ms │     no change │
│ QQuery 53 │   28.69 ms │                                 28.84 ms │     no change │
│ QQuery 54 │   52.63 ms │                                 52.30 ms │     no change │
│ QQuery 55 │   22.69 ms │                                 22.85 ms │     no change │
│ QQuery 56 │   36.60 ms │                                 37.39 ms │     no change │
│ QQuery 57 │  165.20 ms │                                164.97 ms │     no change │
│ QQuery 58 │  106.04 ms │                                105.01 ms │     no change │
│ QQuery 59 │  114.61 ms │                                113.98 ms │     no change │
│ QQuery 60 │   37.64 ms │                                 37.96 ms │     no change │
│ QQuery 61 │   10.79 ms │                                 10.84 ms │     no change │
│ QQuery 62 │   42.55 ms │                                 42.82 ms │     no change │
│ QQuery 63 │   28.77 ms │                                 28.52 ms │     no change │
│ QQuery 64 │  356.97 ms │                                359.36 ms │     no change │
│ QQuery 65 │  126.65 ms │                                130.29 ms │     no change │
│ QQuery 66 │   74.08 ms │                                 74.02 ms │     no change │
│ QQuery 67 │  241.97 ms │                                244.49 ms │     no change │
│ QQuery 68 │   11.64 ms │                                 11.58 ms │     no change │
│ QQuery 69 │   56.34 ms │                                 55.62 ms │     no change │
│ QQuery 70 │  102.86 ms │                                102.13 ms │     no change │
│ QQuery 71 │   34.36 ms │                                 34.06 ms │     no change │
│ QQuery 72 │ 1561.27 ms │                               1516.53 ms │     no change │
│ QQuery 73 │    9.63 ms │                                  9.60 ms │     no change │
│ QQuery 74 │  154.31 ms │                                150.74 ms │     no change │
│ QQuery 75 │  138.10 ms │                                139.11 ms │     no change │
│ QQuery 76 │   33.01 ms │                                 34.15 ms │     no change │
│ QQuery 77 │   59.29 ms │                                 59.03 ms │     no change │
│ QQuery 78 │  158.53 ms │                                157.71 ms │     no change │
│ QQuery 79 │   65.74 ms │                                 65.46 ms │     no change │
│ QQuery 80 │   93.20 ms │                                 93.85 ms │     no change │
│ QQuery 81 │   25.50 ms │                                 25.44 ms │     no change │
│ QQuery 82 │   16.23 ms │                                 16.15 ms │     no change │
│ QQuery 83 │   32.69 ms │                                 32.19 ms │     no change │
│ QQuery 84 │   29.18 ms │                                 29.26 ms │     no change │
│ QQuery 85 │   97.46 ms │                                 97.39 ms │     no change │
│ QQuery 86 │   24.72 ms │                                 24.81 ms │     no change │
│ QQuery 87 │   59.74 ms │                                 59.54 ms │     no change │
│ QQuery 88 │   59.18 ms │                                 58.74 ms │     no change │
│ QQuery 89 │   34.50 ms │                                 34.39 ms │     no change │
│ QQuery 90 │   16.12 ms │                                 15.94 ms │     no change │
│ QQuery 91 │   40.03 ms │                                 40.47 ms │     no change │
│ QQuery 92 │   28.54 ms │                                 29.21 ms │     no change │
│ QQuery 93 │   48.37 ms │                                 48.81 ms │     no change │
│ QQuery 94 │   37.39 ms │                                 36.85 ms │     no change │
│ QQuery 95 │   78.35 ms │                                 78.76 ms │     no change │
│ QQuery 96 │   23.04 ms │                                 23.29 ms │     no change │
│ QQuery 97 │   49.44 ms │                                 51.90 ms │     no change │
│ QQuery 98 │   41.95 ms │                                 41.46 ms │     no change │
│ QQuery 99 │   63.69 ms │                                 63.86 ms │     no change │
└───────────┴────────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 8633.14ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 8597.84ms │
│ Average Time (HEAD)                                     │   87.20ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │   86.85ms │
│ Queries Faster                                          │         2 │
│ Queries Slower                                          │         1 │
│ Queries with No Change                                  │        96 │
│ Queries with Failure                                    │         0 │
└─────────────────────────────────────────────────────────┴───────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │           5.42 / 6.02 ±1.02 / 8.03 ms │              5.48 / 6.06 ±1.02 / 8.11 ms │     no change │
│ QQuery 2  │        79.52 / 79.71 ±0.21 / 80.11 ms │           79.63 / 80.03 ±0.34 / 80.43 ms │     no change │
│ QQuery 3  │        28.07 / 28.39 ±0.26 / 28.86 ms │           28.11 / 28.37 ±0.19 / 28.66 ms │     no change │
│ QQuery 4  │     428.64 / 431.52 ±1.89 / 434.03 ms │        427.69 / 433.05 ±4.37 / 439.07 ms │     no change │
│ QQuery 5  │        49.27 / 49.96 ±0.57 / 50.80 ms │           49.56 / 50.02 ±0.37 / 50.58 ms │     no change │
│ QQuery 6  │        34.13 / 35.29 ±0.87 / 36.77 ms │           34.40 / 36.33 ±2.59 / 41.42 ms │     no change │
│ QQuery 7  │        71.83 / 72.61 ±0.57 / 73.12 ms │           71.95 / 73.18 ±1.02 / 74.37 ms │     no change │
│ QQuery 8  │        35.53 / 35.89 ±0.29 / 36.35 ms │           35.81 / 36.36 ±0.46 / 37.17 ms │     no change │
│ QQuery 9  │        50.74 / 52.83 ±1.23 / 54.18 ms │           50.77 / 53.35 ±2.21 / 56.93 ms │     no change │
│ QQuery 10 │        61.74 / 63.30 ±2.27 / 67.81 ms │           61.42 / 63.43 ±2.99 / 69.39 ms │     no change │
│ QQuery 11 │     261.04 / 265.30 ±3.46 / 271.25 ms │        264.22 / 268.31 ±2.64 / 272.49 ms │     no change │
│ QQuery 12 │        28.34 / 28.94 ±0.40 / 29.43 ms │           28.31 / 28.70 ±0.30 / 29.12 ms │     no change │
│ QQuery 13 │     111.88 / 112.90 ±0.96 / 114.71 ms │        111.92 / 114.06 ±1.42 / 116.11 ms │     no change │
│ QQuery 14 │     382.80 / 389.27 ±4.06 / 394.08 ms │        380.70 / 384.02 ±2.43 / 387.26 ms │     no change │
│ QQuery 15 │        51.27 / 53.59 ±2.80 / 59.08 ms │           52.04 / 53.58 ±1.45 / 56.30 ms │     no change │
│ QQuery 16 │           6.20 / 6.31 ±0.18 / 6.66 ms │              5.51 / 5.68 ±0.20 / 6.07 ms │ +1.11x faster │
│ QQuery 17 │        78.98 / 79.41 ±0.40 / 79.98 ms │           77.83 / 78.07 ±0.16 / 78.27 ms │     no change │
│ QQuery 18 │     102.77 / 105.49 ±2.54 / 110.29 ms │        103.49 / 104.86 ±1.32 / 107.35 ms │     no change │
│ QQuery 19 │        40.90 / 41.33 ±0.37 / 41.84 ms │           40.78 / 41.04 ±0.18 / 41.23 ms │     no change │
│ QQuery 20 │        35.30 / 35.94 ±0.67 / 36.87 ms │           35.07 / 35.18 ±0.11 / 35.36 ms │     no change │
│ QQuery 21 │        16.52 / 17.33 ±1.26 / 19.83 ms │           16.40 / 17.31 ±1.04 / 19.27 ms │     no change │
│ QQuery 22 │        62.15 / 62.84 ±0.39 / 63.30 ms │           62.80 / 63.15 ±0.30 / 63.62 ms │     no change │
│ QQuery 23 │     299.29 / 304.57 ±4.68 / 311.02 ms │        299.83 / 302.09 ±2.39 / 306.19 ms │     no change │
│ QQuery 24 │     189.60 / 194.38 ±5.91 / 205.90 ms │        189.43 / 193.47 ±4.36 / 201.89 ms │     no change │
│ QQuery 25 │     107.82 / 109.31 ±1.21 / 110.79 ms │        106.95 / 108.29 ±1.29 / 110.07 ms │     no change │
│ QQuery 26 │        45.49 / 47.45 ±2.63 / 52.65 ms │           45.27 / 47.49 ±2.88 / 53.11 ms │     no change │
│ QQuery 27 │           5.79 / 6.03 ±0.25 / 6.51 ms │              5.81 / 6.06 ±0.26 / 6.49 ms │     no change │
│ QQuery 28 │        55.00 / 57.61 ±2.18 / 60.97 ms │           60.08 / 60.53 ±0.36 / 60.97 ms │  1.05x slower │
│ QQuery 29 │        94.14 / 95.80 ±1.33 / 98.00 ms │           95.50 / 96.48 ±1.40 / 99.15 ms │     no change │
│ QQuery 30 │        32.64 / 34.26 ±2.09 / 38.34 ms │           31.94 / 33.76 ±2.70 / 39.12 ms │     no change │
│ QQuery 31 │     105.84 / 107.20 ±1.27 / 109.59 ms │        107.09 / 107.88 ±0.86 / 109.14 ms │     no change │
│ QQuery 32 │        20.02 / 20.14 ±0.16 / 20.45 ms │           19.43 / 19.87 ±0.50 / 20.78 ms │     no change │
│ QQuery 33 │        35.91 / 36.70 ±0.47 / 37.18 ms │           36.15 / 36.68 ±0.39 / 37.15 ms │     no change │
│ QQuery 34 │          9.69 / 9.94 ±0.21 / 10.32 ms │            9.76 / 10.02 ±0.19 / 10.23 ms │     no change │
│ QQuery 35 │        70.62 / 72.70 ±2.08 / 76.37 ms │           70.50 / 72.80 ±2.31 / 76.99 ms │     no change │
│ QQuery 36 │           5.51 / 5.67 ±0.28 / 6.22 ms │              5.43 / 5.57 ±0.24 / 6.05 ms │     no change │
│ QQuery 37 │           6.57 / 6.72 ±0.10 / 6.88 ms │              6.52 / 6.61 ±0.06 / 6.67 ms │     no change │
│ QQuery 38 │        60.02 / 60.64 ±0.75 / 62.10 ms │           59.40 / 59.95 ±0.45 / 60.65 ms │     no change │
│ QQuery 39 │        71.53 / 73.96 ±3.90 / 81.70 ms │           71.64 / 73.02 ±1.54 / 76.04 ms │     no change │
│ QQuery 40 │        23.38 / 24.36 ±0.62 / 25.12 ms │           22.17 / 23.58 ±1.07 / 24.68 ms │     no change │
│ QQuery 41 │        10.97 / 11.21 ±0.28 / 11.74 ms │           11.04 / 11.14 ±0.09 / 11.29 ms │     no change │
│ QQuery 42 │        22.91 / 23.54 ±0.51 / 24.47 ms │           22.91 / 23.56 ±0.53 / 24.36 ms │     no change │
│ QQuery 43 │           4.63 / 4.72 ±0.17 / 5.06 ms │              4.69 / 4.83 ±0.21 / 5.25 ms │     no change │
│ QQuery 44 │           8.50 / 8.62 ±0.10 / 8.78 ms │              8.59 / 8.64 ±0.04 / 8.71 ms │     no change │
│ QQuery 45 │        35.60 / 35.91 ±0.27 / 36.32 ms │           35.13 / 35.57 ±0.23 / 35.77 ms │     no change │
│ QQuery 46 │        11.45 / 12.12 ±1.13 / 14.36 ms │           11.43 / 12.68 ±1.66 / 15.95 ms │     no change │
│ QQuery 47 │     214.57 / 219.61 ±4.51 / 227.51 ms │        215.34 / 218.62 ±2.41 / 221.02 ms │     no change │
│ QQuery 48 │        90.01 / 91.07 ±1.56 / 94.14 ms │           89.35 / 91.15 ±2.26 / 95.60 ms │     no change │
│ QQuery 49 │        68.33 / 69.39 ±1.32 / 71.89 ms │           68.31 / 69.26 ±1.05 / 71.22 ms │     no change │
│ QQuery 50 │        58.02 / 58.86 ±0.89 / 60.45 ms │           57.54 / 58.80 ±1.33 / 61.32 ms │     no change │
│ QQuery 51 │        92.75 / 95.52 ±2.45 / 99.76 ms │          91.56 / 95.77 ±6.09 / 107.89 ms │     no change │
│ QQuery 52 │        23.21 / 23.69 ±0.43 / 24.28 ms │           23.49 / 23.88 ±0.34 / 24.49 ms │     no change │
│ QQuery 53 │        28.69 / 28.88 ±0.15 / 29.07 ms │           28.84 / 29.00 ±0.10 / 29.15 ms │     no change │
│ QQuery 54 │        52.63 / 53.24 ±0.56 / 54.23 ms │           52.30 / 53.60 ±1.39 / 56.23 ms │     no change │
│ QQuery 55 │        22.69 / 22.99 ±0.19 / 23.26 ms │           22.85 / 23.14 ±0.29 / 23.55 ms │     no change │
│ QQuery 56 │        36.60 / 37.36 ±0.43 / 37.91 ms │           37.39 / 39.23 ±2.19 / 43.41 ms │     no change │
│ QQuery 57 │     165.20 / 166.11 ±0.81 / 167.52 ms │        164.97 / 166.52 ±1.65 / 169.49 ms │     no change │
│ QQuery 58 │     106.04 / 107.96 ±2.61 / 112.99 ms │        105.01 / 107.60 ±2.45 / 111.84 ms │     no change │
│ QQuery 59 │     114.61 / 115.43 ±0.64 / 116.45 ms │        113.98 / 115.16 ±1.42 / 117.94 ms │     no change │
│ QQuery 60 │        37.64 / 38.27 ±0.81 / 39.86 ms │           37.96 / 38.52 ±0.41 / 39.23 ms │     no change │
│ QQuery 61 │        10.79 / 10.94 ±0.23 / 11.39 ms │           10.84 / 10.96 ±0.16 / 11.27 ms │     no change │
│ QQuery 62 │        42.55 / 42.88 ±0.20 / 43.08 ms │           42.82 / 43.35 ±0.41 / 43.82 ms │     no change │
│ QQuery 63 │        28.77 / 29.47 ±0.97 / 31.38 ms │           28.52 / 30.05 ±1.69 / 33.27 ms │     no change │
│ QQuery 64 │     356.97 / 359.47 ±1.79 / 361.47 ms │        359.36 / 362.27 ±4.01 / 370.21 ms │     no change │
│ QQuery 65 │     126.65 / 130.47 ±4.64 / 139.13 ms │        130.29 / 132.53 ±2.36 / 135.85 ms │     no change │
│ QQuery 66 │        74.08 / 74.74 ±0.45 / 75.20 ms │           74.02 / 74.63 ±0.52 / 75.46 ms │     no change │
│ QQuery 67 │     241.97 / 247.66 ±5.87 / 258.83 ms │        244.49 / 247.19 ±2.95 / 250.89 ms │     no change │
│ QQuery 68 │        11.64 / 11.83 ±0.16 / 12.13 ms │           11.58 / 11.81 ±0.19 / 12.14 ms │     no change │
│ QQuery 69 │        56.34 / 58.39 ±2.05 / 61.81 ms │           55.62 / 56.24 ±0.44 / 56.82 ms │     no change │
│ QQuery 70 │     102.86 / 104.05 ±0.80 / 104.89 ms │        102.13 / 106.12 ±5.47 / 116.84 ms │     no change │
│ QQuery 71 │        34.36 / 34.97 ±0.53 / 35.82 ms │           34.06 / 34.95 ±0.87 / 36.45 ms │     no change │
│ QQuery 72 │ 1561.27 / 1609.86 ±39.36 / 1666.54 ms │    1516.53 / 1654.61 ±69.41 / 1698.50 ms │     no change │
│ QQuery 73 │          9.63 / 9.90 ±0.35 / 10.58 ms │            9.60 / 10.20 ±0.39 / 10.69 ms │     no change │
│ QQuery 74 │     154.31 / 155.01 ±0.88 / 156.73 ms │        150.74 / 155.23 ±3.87 / 162.21 ms │     no change │
│ QQuery 75 │     138.10 / 140.89 ±2.66 / 145.94 ms │        139.11 / 141.09 ±3.07 / 147.15 ms │     no change │
│ QQuery 76 │        33.01 / 33.44 ±0.39 / 34.11 ms │           34.15 / 35.61 ±2.04 / 39.59 ms │  1.06x slower │
│ QQuery 77 │        59.29 / 60.08 ±0.82 / 61.56 ms │           59.03 / 59.30 ±0.33 / 59.91 ms │     no change │
│ QQuery 78 │     158.53 / 161.03 ±2.33 / 165.37 ms │        157.71 / 163.53 ±6.19 / 175.49 ms │     no change │
│ QQuery 79 │        65.74 / 66.55 ±0.62 / 67.63 ms │           65.46 / 67.98 ±4.35 / 76.67 ms │     no change │
│ QQuery 80 │        93.20 / 95.03 ±2.23 / 99.30 ms │          93.85 / 96.27 ±2.81 / 101.72 ms │     no change │
│ QQuery 81 │        25.50 / 25.69 ±0.17 / 25.90 ms │           25.44 / 25.66 ±0.30 / 26.21 ms │     no change │
│ QQuery 82 │        16.23 / 16.50 ±0.18 / 16.69 ms │           16.15 / 16.41 ±0.27 / 16.93 ms │     no change │
│ QQuery 83 │        32.69 / 33.35 ±1.06 / 35.46 ms │           32.19 / 32.59 ±0.27 / 33.04 ms │     no change │
│ QQuery 84 │        29.18 / 29.73 ±0.51 / 30.61 ms │           29.26 / 31.05 ±2.12 / 35.05 ms │     no change │
│ QQuery 85 │       97.46 / 99.94 ±2.39 / 104.27 ms │          97.39 / 99.88 ±2.00 / 102.10 ms │     no change │
│ QQuery 86 │        24.72 / 24.94 ±0.18 / 25.15 ms │           24.81 / 25.32 ±0.32 / 25.75 ms │     no change │
│ QQuery 87 │        59.74 / 60.27 ±0.33 / 60.62 ms │           59.54 / 60.22 ±0.66 / 61.25 ms │     no change │
│ QQuery 88 │        59.18 / 60.22 ±1.03 / 62.13 ms │           58.74 / 60.76 ±2.70 / 66.09 ms │     no change │
│ QQuery 89 │        34.50 / 35.14 ±0.43 / 35.62 ms │           34.39 / 35.25 ±1.05 / 37.29 ms │     no change │
│ QQuery 90 │        16.12 / 16.33 ±0.19 / 16.70 ms │           15.94 / 16.18 ±0.27 / 16.70 ms │     no change │
│ QQuery 91 │        40.03 / 40.55 ±0.47 / 41.40 ms │           40.47 / 40.72 ±0.14 / 40.85 ms │     no change │
│ QQuery 92 │        28.54 / 29.80 ±1.37 / 32.33 ms │           29.21 / 29.79 ±0.35 / 30.15 ms │     no change │
│ QQuery 93 │        48.37 / 49.60 ±1.42 / 52.30 ms │           48.81 / 50.73 ±2.10 / 54.81 ms │     no change │
│ QQuery 94 │        37.39 / 38.46 ±0.76 / 39.39 ms │           36.85 / 37.37 ±0.50 / 38.25 ms │     no change │
│ QQuery 95 │        78.35 / 79.47 ±0.63 / 80.10 ms │           78.76 / 80.48 ±1.70 / 83.22 ms │     no change │
│ QQuery 96 │        23.04 / 23.34 ±0.29 / 23.87 ms │           23.29 / 23.62 ±0.33 / 24.18 ms │     no change │
│ QQuery 97 │        49.44 / 50.89 ±1.22 / 53.13 ms │           51.90 / 53.35 ±1.52 / 56.20 ms │     no change │
│ QQuery 98 │        41.95 / 42.75 ±0.71 / 43.76 ms │           41.46 / 42.26 ±0.64 / 43.17 ms │     no change │
│ QQuery 99 │        63.69 / 64.16 ±0.40 / 64.81 ms │           63.86 / 64.81 ±0.99 / 66.67 ms │     no change │
└───────────┴───────────────────────────────────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 8803.90ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 8865.30ms │
│ Average Time (HEAD)                                     │   88.93ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │   89.55ms │
│ Queries Faster                                          │         1 │
│ Queries Slower                                          │         2 │
│ Queries with No Change                                  │        96 │
│ Queries with Failure                                    │         0 │
└─────────────────────────────────────────────────────────┴───────────┘

Resource Usage

tpcds — base (merge-base)

Metric Value
Wall time 45.0s
Peak memory 2.2 GiB
Avg memory 1.5 GiB
CPU user 190.5s
CPU sys 5.2s
Peak spill 0 B

tpcds — branch

Metric Value
Wall time 45.0s
Peak memory 2.1 GiB
Avg memory 1.4 GiB
CPU user 187.3s
CPU sys 5.4s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing fix/single-distinct-groupby-memory-usage (0923424) to 334f293 (merge-base) diff

Run configuration
run benchmark clickbench_partitioned
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ fix_single-distinct-groupby-memory-usage ┃       Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ QQuery 0  │    1.21 ms │                                  1.24 ms │    no change │
│ QQuery 1  │   11.53 ms │                                 11.81 ms │    no change │
│ QQuery 2  │   36.03 ms │                                 36.11 ms │    no change │
│ QQuery 3  │   32.65 ms │                                 31.71 ms │    no change │
│ QQuery 4  │  242.63 ms │                                632.82 ms │ 2.61x slower │
│ QQuery 5  │  287.61 ms │                                277.62 ms │    no change │
│ QQuery 6  │    1.29 ms │                                  1.23 ms │    no change │
│ QQuery 7  │   13.36 ms │                                 12.91 ms │    no change │
│ QQuery 8  │  349.51 ms │                                376.25 ms │ 1.08x slower │
│ QQuery 9  │  475.90 ms │                                481.50 ms │    no change │
│ QQuery 10 │   65.62 ms │                                 96.97 ms │ 1.48x slower │
│ QQuery 11 │   76.46 ms │                                102.84 ms │ 1.34x slower │
│ QQuery 12 │  272.83 ms │                                266.34 ms │    no change │
│ QQuery 13 │  380.95 ms │                                392.40 ms │    no change │
│ QQuery 14 │  294.61 ms │                                285.95 ms │    no change │
│ QQuery 15 │  294.13 ms │                                300.89 ms │    no change │
│ QQuery 16 │  632.64 ms │                                625.71 ms │    no change │
│ QQuery 17 │  653.41 ms │                                639.50 ms │    no change │
│ QQuery 18 │ 1309.92 ms │                               1333.86 ms │    no change │
│ QQuery 19 │   29.19 ms │                                 27.93 ms │    no change │
│ QQuery 20 │  532.89 ms │                                527.14 ms │    no change │
│ QQuery 21 │  535.80 ms │                                528.26 ms │    no change │
│ QQuery 22 │ 1025.70 ms │                               1020.79 ms │    no change │
│ QQuery 23 │ 3176.32 ms │                               3262.30 ms │    no change │
│ QQuery 24 │   42.25 ms │                                 44.83 ms │ 1.06x slower │
│ QQuery 25 │  108.71 ms │                                107.64 ms │    no change │
│ QQuery 26 │   42.42 ms │                                 42.10 ms │    no change │
│ QQuery 27 │  528.52 ms │                                523.45 ms │    no change │
│ QQuery 28 │ 2938.42 ms │                               2931.53 ms │    no change │
│ QQuery 29 │   39.47 ms │                                 39.54 ms │    no change │
│ QQuery 30 │  323.15 ms │                                318.40 ms │    no change │
│ QQuery 31 │  289.84 ms │                                299.37 ms │    no change │
│ QQuery 32 │ 1165.77 ms │                               1156.05 ms │    no change │
│ QQuery 33 │ 1643.33 ms │                               1644.54 ms │    no change │
│ QQuery 34 │ 1599.86 ms │                               1732.76 ms │ 1.08x slower │
│ QQuery 35 │  311.22 ms │                                308.49 ms │    no change │
│ QQuery 36 │   67.88 ms │                                 66.64 ms │    no change │
│ QQuery 37 │   35.94 ms │                                 35.54 ms │    no change │
│ QQuery 38 │   40.92 ms │                                 44.41 ms │ 1.09x slower │
│ QQuery 39 │  142.77 ms │                                148.70 ms │    no change │
│ QQuery 40 │   14.09 ms │                                 14.70 ms │    no change │
│ QQuery 41 │   13.81 ms │                                 14.57 ms │ 1.06x slower │
│ QQuery 42 │   13.79 ms │                                 13.79 ms │    no change │
└───────────┴────────────┴──────────────────────────────────────────┴──────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 20094.34ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 20761.13ms │
│ Average Time (HEAD)                                     │   467.31ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │   482.82ms │
│ Queries Faster                                          │          0 │
│ Queries Slower                                          │          8 │
│ Queries with No Change                                  │         35 │
│ Queries with Failure                                    │          0 │
└─────────────────────────────────────────────────────────┴────────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                   HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 0  │           1.21 / 4.43 ±6.29 / 17.01 ms │             1.24 / 4.58 ±6.47 / 17.51 ms │     no change │
│ QQuery 1  │         11.53 / 11.89 ±0.19 / 12.10 ms │           11.81 / 12.12 ±0.16 / 12.26 ms │     no change │
│ QQuery 2  │         36.03 / 36.38 ±0.28 / 36.82 ms │           36.11 / 36.38 ±0.26 / 36.85 ms │     no change │
│ QQuery 3  │         32.65 / 33.14 ±0.59 / 34.04 ms │           31.71 / 32.12 ±0.48 / 33.02 ms │     no change │
│ QQuery 4  │      242.63 / 248.76 ±4.65 / 254.88 ms │        632.82 / 640.21 ±6.94 / 653.00 ms │  2.57x slower │
│ QQuery 5  │      287.61 / 290.33 ±1.85 / 293.06 ms │        277.62 / 281.84 ±2.32 / 284.76 ms │     no change │
│ QQuery 6  │            1.29 / 1.44 ±0.23 / 1.89 ms │              1.23 / 1.40 ±0.26 / 1.90 ms │     no change │
│ QQuery 7  │         13.36 / 13.65 ±0.22 / 13.94 ms │           12.91 / 13.16 ±0.14 / 13.35 ms │     no change │
│ QQuery 8  │      349.51 / 355.51 ±3.20 / 358.77 ms │       376.25 / 402.63 ±13.83 / 416.80 ms │  1.13x slower │
│ QQuery 9  │      475.90 / 482.99 ±5.10 / 490.11 ms │       481.50 / 500.32 ±15.59 / 522.19 ms │     no change │
│ QQuery 10 │         65.62 / 66.63 ±1.00 / 68.16 ms │         96.97 / 106.35 ±5.24 / 110.67 ms │  1.60x slower │
│ QQuery 11 │         76.46 / 76.75 ±0.23 / 77.09 ms │        102.84 / 106.76 ±2.42 / 110.23 ms │  1.39x slower │
│ QQuery 12 │      272.83 / 280.35 ±5.87 / 290.56 ms │       266.34 / 279.84 ±15.02 / 308.77 ms │     no change │
│ QQuery 13 │     380.95 / 397.57 ±19.27 / 433.55 ms │        392.40 / 402.56 ±9.28 / 416.14 ms │     no change │
│ QQuery 14 │      294.61 / 301.79 ±7.45 / 311.21 ms │        285.95 / 296.12 ±8.23 / 308.16 ms │     no change │
│ QQuery 15 │      294.13 / 305.86 ±9.51 / 322.73 ms │       300.89 / 314.38 ±14.12 / 341.32 ms │     no change │
│ QQuery 16 │     632.64 / 651.45 ±16.62 / 679.17 ms │        625.71 / 639.86 ±7.29 / 645.09 ms │     no change │
│ QQuery 17 │     653.41 / 667.01 ±10.17 / 680.65 ms │       639.50 / 666.96 ±16.17 / 686.63 ms │     no change │
│ QQuery 18 │  1309.92 / 1340.50 ±21.83 / 1374.01 ms │    1333.86 / 1347.92 ±14.13 / 1368.19 ms │     no change │
│ QQuery 19 │         29.19 / 36.96 ±9.98 / 54.17 ms │           27.93 / 29.85 ±3.32 / 36.46 ms │ +1.24x faster │
│ QQuery 20 │     532.89 / 542.48 ±10.77 / 563.55 ms │       527.14 / 538.96 ±12.15 / 561.71 ms │     no change │
│ QQuery 21 │      535.80 / 539.31 ±3.49 / 545.50 ms │        528.26 / 536.10 ±8.35 / 549.51 ms │     no change │
│ QQuery 22 │  1025.70 / 1055.17 ±21.43 / 1082.55 ms │    1020.79 / 1077.26 ±45.78 / 1142.31 ms │     no change │
│ QQuery 23 │ 3176.32 / 3424.21 ±141.60 / 3592.26 ms │    3262.30 / 3330.05 ±63.05 / 3447.61 ms │     no change │
│ QQuery 24 │     42.25 / 186.85 ±141.79 / 358.50 ms │       44.83 / 164.26 ±131.18 / 398.39 ms │ +1.14x faster │
│ QQuery 25 │      108.71 / 110.60 ±1.98 / 113.99 ms │        107.64 / 109.55 ±1.38 / 110.85 ms │     no change │
│ QQuery 26 │         42.42 / 43.49 ±0.84 / 44.67 ms │           42.10 / 43.28 ±0.97 / 44.64 ms │     no change │
│ QQuery 27 │      528.52 / 536.13 ±7.33 / 549.30 ms │        523.45 / 527.87 ±3.95 / 533.59 ms │     no change │
│ QQuery 28 │  2938.42 / 2980.13 ±33.70 / 3036.62 ms │    2931.53 / 2976.17 ±25.72 / 2999.24 ms │     no change │
│ QQuery 29 │        39.47 / 53.11 ±16.19 / 75.46 ms │           39.54 / 40.01 ±0.32 / 40.42 ms │ +1.33x faster │
│ QQuery 30 │      323.15 / 332.83 ±8.61 / 346.93 ms │        318.40 / 327.50 ±5.39 / 334.77 ms │     no change │
│ QQuery 31 │      289.84 / 296.37 ±4.24 / 301.76 ms │        299.37 / 300.87 ±1.99 / 304.76 ms │     no change │
│ QQuery 32 │  1165.77 / 1240.12 ±68.48 / 1356.63 ms │    1156.05 / 1231.14 ±67.76 / 1341.70 ms │     no change │
│ QQuery 33 │  1643.33 / 1669.20 ±19.52 / 1689.05 ms │    1644.54 / 1701.23 ±55.20 / 1783.59 ms │     no change │
│ QQuery 34 │  1599.86 / 1685.77 ±46.07 / 1720.38 ms │    1732.76 / 1790.47 ±61.66 / 1897.45 ms │  1.06x slower │
│ QQuery 35 │    311.22 / 396.36 ±141.72 / 678.99 ms │      308.49 / 458.84 ±268.06 / 994.42 ms │  1.16x slower │
│ QQuery 36 │         67.88 / 73.03 ±6.84 / 86.30 ms │           66.64 / 72.60 ±4.78 / 81.05 ms │     no change │
│ QQuery 37 │         35.94 / 36.72 ±0.60 / 37.69 ms │           35.54 / 41.81 ±9.56 / 60.47 ms │  1.14x slower │
│ QQuery 38 │        40.92 / 55.00 ±20.38 / 95.36 ms │          44.41 / 55.05 ±10.54 / 73.37 ms │     no change │
│ QQuery 39 │      142.77 / 154.62 ±7.58 / 166.27 ms │        148.70 / 155.60 ±4.28 / 161.45 ms │     no change │
│ QQuery 40 │         14.09 / 14.62 ±0.41 / 15.36 ms │           14.70 / 16.96 ±3.76 / 24.46 ms │  1.16x slower │
│ QQuery 41 │         13.81 / 18.06 ±8.21 / 34.47 ms │           14.57 / 19.11 ±6.80 / 32.39 ms │  1.06x slower │
│ QQuery 42 │         13.79 / 21.24 ±6.35 / 28.43 ms │           13.79 / 14.04 ±0.21 / 14.33 ms │ +1.51x faster │
└───────────┴────────────────────────────────────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 21068.81ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 21644.10ms │
│ Average Time (HEAD)                                     │   489.97ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │   503.35ms │
│ Queries Faster                                          │          4 │
│ Queries Slower                                          │          9 │
│ Queries with No Change                                  │         30 │
│ Queries with Failure                                    │          0 │
└─────────────────────────────────────────────────────────┴────────────┘

Resource Usage

clickbench_partitioned — base (merge-base)

Metric Value
Wall time 110.0s
Peak memory 18.6 GiB
Avg memory 5.9 GiB
CPU user 1030.1s
CPU sys 108.4s
Peak spill 0 B

clickbench_partitioned — branch

Metric Value
Wall time 110.0s
Peak memory 17.7 GiB
Avg memory 6.2 GiB
CPU user 1025.3s
CPU sys 110.6s
Peak spill 0 B

File an issue against this benchmark runner

@mkleen

mkleen commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

@mohitgurav20 There are serious performance regressions in the clickhouse benchmark. See #26000 (comment) for more details.

@mohitgurav20

Copy link
Copy Markdown
Contributor Author

Thanks for running the benchmark and flagging this @mkleen.

I analyzed the benchmark run in detail:
Every single regressed query (Q4, Q8, Q10, Q11, Q34, Q35, Q37, Q40, Q41) is a COUNT(DISTINCT "UserID") query where "UserID" is Int64.

Because count.groups_accumulator_supported_for_types(&[Int64], true) returns Some(true), the unconditional rewrite_pays check prevented SingleDistinctToGroupBy from firing on lone distinct queries like SELECT COUNT(DISTINCT UserID) FROM hits.

Without the two-phase rewrite to GROUP BY, the engine cannot leverage RepartitionExec: partitioning=Hash(...) to parallelize deduplication across partitions, and falls back to evaluating distincts serially through the accumulator. That explains the 2.57x regression on Q4 (248 ms -> 640 ms) and the slowdowns on Q10 and Q11.

This confirms that the two-phase rewrite is a critical parallelization optimization for lone distinct queries, even when a specialized GroupsAccumulator exists.

To address this cleanly:
Lone distinct queries (where all aggregates in the plan are DISTINCT on the same expression, with no companion non-distinct aggregates) should always be rewritten to preserve parallel hash aggregation. The heuristic gating should only apply when non-distinct companion aggregates (like count(*) or sum(y)) are present.

Does that direction sound good to you? If so, I'll update the rule accordingly so we preserve ClickBench performance.

…pache#25932)

SingleDistinctToGroupBy converts single DISTINCT aggregate expressions into
a two-phase GROUP BY plan. This enables parallel deduplication via
RepartitionExec hash partitioning, which is critical for lone-distinct
queries like COUNT(DISTINCT x).

However, when companion non-distinct aggregates are present alongside the
distinct aggregate (e.g. SELECT sum(y), count(DISTINCT x)), the companion
aggregates move to the inner group-by at a finer grain. When the distinct
aggregate already has native GroupsAccumulator support, this inner grouping
adds unnecessary memory and CPU overhead without benefiting from adapter
offloading.

This change:
1. Gates SingleDistinctToGroupBy with rewrite_pays() only when companion
   non-distinct aggregates are present.
2. Preserves the two-phase rewrite for pure lone-distinct queries so ClickBench
   and similar workloads maintain parallel deduplication without regression.
3. Consistently handles distinct aggregates with unsupported distinct handling.
4. Updates optimizer plan snapshots and sqllogictests.
@mohitgurav20
mohitgurav20 force-pushed the fix/single-distinct-groupby-memory-usage branch from 287b932 to ac76b0d Compare October 17, 2026 07:46
@mohitgurav20

Copy link
Copy Markdown
Contributor Author

Hi @mkleen, just following up on this when you get a chance.

I've rebased cleanly onto latest main and addressed the ClickBench regression — lone-distinct queries now always retain the 2-phase GROUP BY fanout, while the cost guard only applies when companion aggregates are present. CI and coverage checks are all passing.

Could you trigger a benchmark run whenever convenient? Thanks!

@mkleen

mkleen commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

run benchmarks

@adriangbot

Copy link
Copy Markdown

Benchmark for this request failed before finishing (Kubernetes reason: BackoffLimitExceeded).

Benchmarks requested: clickbench_partitioned

Kubernetes message
Job has reached the specified backoff limit

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c6235987877-3544-tdnvp 6.12.94+ #1 SMP Fri Aug 21 08:00:16 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing fix/single-distinct-groupby-memory-usage (bbf4ccb) to 484183d (merge-base) diff

Run configuration
run benchmark tpch

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c6235987877-3543-kmxlp 6.12.94+ #1 SMP Fri Aug 21 08:00:16 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing fix/single-distinct-groupby-memory-usage (bbf4ccb) to 484183d (merge-base) diff

Run configuration
run benchmark tpcds

Results will be posted here when complete


File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing fix/single-distinct-groupby-memory-usage (bbf4ccb) to 484183d (merge-base) diff

Run configuration
run benchmark tpch
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Query     ┃     HEAD ┃ fix_single-distinct-groupby-memory-usage ┃    Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ QQuery 1  │ 40.67 ms │                                 40.37 ms │ no change │
│ QQuery 2  │ 18.39 ms │                                 18.09 ms │ no change │
│ QQuery 3  │ 28.50 ms │                                 28.33 ms │ no change │
│ QQuery 4  │ 17.29 ms │                                 17.34 ms │ no change │
│ QQuery 5  │ 35.11 ms │                                 35.10 ms │ no change │
│ QQuery 6  │ 13.51 ms │                                 13.59 ms │ no change │
│ QQuery 7  │ 41.82 ms │                                 42.07 ms │ no change │
│ QQuery 8  │ 40.50 ms │                                 40.89 ms │ no change │
│ QQuery 9  │ 50.27 ms │                                 50.25 ms │ no change │
│ QQuery 10 │ 40.05 ms │                                 39.91 ms │ no change │
│ QQuery 11 │ 13.35 ms │                                 13.22 ms │ no change │
│ QQuery 12 │ 18.08 ms │                                 18.14 ms │ no change │
│ QQuery 13 │ 39.00 ms │                                 38.85 ms │ no change │
│ QQuery 14 │ 24.47 ms │                                 24.35 ms │ no change │
│ QQuery 15 │ 30.59 ms │                                 30.87 ms │ no change │
│ QQuery 16 │ 13.79 ms │                                 13.68 ms │ no change │
│ QQuery 17 │ 73.73 ms │                                 74.40 ms │ no change │
│ QQuery 18 │ 45.89 ms │                                 44.98 ms │ no change │
│ QQuery 19 │ 31.69 ms │                                 31.94 ms │ no change │
│ QQuery 20 │ 31.72 ms │                                 31.52 ms │ no change │
│ QQuery 21 │ 55.44 ms │                                 55.01 ms │ no change │
│ QQuery 22 │ 13.86 ms │                                 13.58 ms │ no change │
└───────────┴──────────┴──────────────────────────────────────────┴───────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 717.73ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 716.49ms │
│ Average Time (HEAD)                                     │  32.62ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │  32.57ms │
│ Queries Faster                                          │        0 │
│ Queries Slower                                          │        0 │
│ Queries with No Change                                  │       22 │
│ Queries with Failure                                    │        0 │
└─────────────────────────────────────────────────────────┴──────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                           HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │ 40.67 / 42.14 ±1.51 / 44.08 ms │           40.37 / 41.96 ±1.30 / 43.33 ms │     no change │
│ QQuery 2  │ 18.39 / 19.19 ±0.90 / 20.40 ms │           18.09 / 18.49 ±0.34 / 19.07 ms │     no change │
│ QQuery 3  │ 28.50 / 28.76 ±0.18 / 28.92 ms │           28.33 / 28.65 ±0.32 / 29.17 ms │     no change │
│ QQuery 4  │ 17.29 / 17.49 ±0.16 / 17.72 ms │           17.34 / 17.66 ±0.45 / 18.56 ms │     no change │
│ QQuery 5  │ 35.11 / 35.42 ±0.16 / 35.60 ms │           35.10 / 35.40 ±0.37 / 36.10 ms │     no change │
│ QQuery 6  │ 13.51 / 13.88 ±0.49 / 14.85 ms │           13.59 / 14.13 ±0.58 / 15.19 ms │     no change │
│ QQuery 7  │ 41.82 / 43.34 ±1.48 / 45.84 ms │           42.07 / 44.04 ±1.45 / 46.47 ms │     no change │
│ QQuery 8  │ 40.50 / 41.22 ±0.78 / 42.72 ms │           40.89 / 42.57 ±1.51 / 44.91 ms │     no change │
│ QQuery 9  │ 50.27 / 54.13 ±5.41 / 64.89 ms │           50.25 / 51.03 ±0.42 / 51.48 ms │ +1.06x faster │
│ QQuery 10 │ 40.05 / 41.52 ±1.68 / 44.76 ms │           39.91 / 40.32 ±0.25 / 40.60 ms │     no change │
│ QQuery 11 │ 13.35 / 13.51 ±0.18 / 13.82 ms │           13.22 / 13.44 ±0.23 / 13.84 ms │     no change │
│ QQuery 12 │ 18.08 / 18.40 ±0.44 / 19.27 ms │           18.14 / 18.36 ±0.21 / 18.65 ms │     no change │
│ QQuery 13 │ 39.00 / 40.81 ±1.87 / 44.16 ms │           38.85 / 39.20 ±0.30 / 39.74 ms │     no change │
│ QQuery 14 │ 24.47 / 24.66 ±0.15 / 24.81 ms │           24.35 / 24.64 ±0.16 / 24.83 ms │     no change │
│ QQuery 15 │ 30.59 / 31.64 ±1.28 / 33.91 ms │           30.87 / 31.52 ±0.80 / 33.08 ms │     no change │
│ QQuery 16 │ 13.79 / 13.91 ±0.12 / 14.11 ms │           13.68 / 13.80 ±0.15 / 14.07 ms │     no change │
│ QQuery 17 │ 73.73 / 77.96 ±2.40 / 80.84 ms │           74.40 / 75.50 ±1.06 / 77.01 ms │     no change │
│ QQuery 18 │ 45.89 / 47.52 ±1.90 / 50.68 ms │           44.98 / 45.83 ±0.58 / 46.78 ms │     no change │
│ QQuery 19 │ 31.69 / 31.89 ±0.16 / 32.11 ms │           31.94 / 33.24 ±1.46 / 35.38 ms │     no change │
│ QQuery 20 │ 31.72 / 32.78 ±1.51 / 35.77 ms │           31.52 / 31.95 ±0.43 / 32.76 ms │     no change │
│ QQuery 21 │ 55.44 / 57.10 ±2.33 / 61.65 ms │           55.01 / 56.23 ±1.22 / 58.38 ms │     no change │
│ QQuery 22 │ 13.86 / 13.95 ±0.07 / 14.04 ms │           13.58 / 13.86 ±0.30 / 14.39 ms │     no change │
└───────────┴────────────────────────────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 741.21ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 731.82ms │
│ Average Time (HEAD)                                     │  33.69ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │  33.26ms │
│ Queries Faster                                          │        1 │
│ Queries Slower                                          │        0 │
│ Queries with No Change                                  │       21 │
│ Queries with Failure                                    │        0 │
└─────────────────────────────────────────────────────────┴──────────┘

Resource Usage

tpch — base (merge-base)

Metric Value
Wall time 5.0s
Peak memory 1.1 GiB
Avg memory 480.6 MiB
CPU user 20.0s
CPU sys 1.7s
Peak spill 0 B

tpch — branch

Metric Value
Wall time 5.0s
Peak memory 1.1 GiB
Avg memory 489.3 MiB
CPU user 19.9s
CPU sys 1.6s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

Comparing fix/single-distinct-groupby-memory-usage (bbf4ccb) to 484183d (merge-base) diff

Run configuration
run benchmark tpcds
CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃       HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │    5.76 ms │                                  5.61 ms │     no change │
│ QQuery 2  │   83.34 ms │                                 82.53 ms │     no change │
│ QQuery 3  │   29.31 ms │                                 28.98 ms │     no change │
│ QQuery 4  │  502.51 ms │                                500.69 ms │     no change │
│ QQuery 5  │   52.20 ms │                                 50.92 ms │     no change │
│ QQuery 6  │   37.43 ms │                                 37.04 ms │     no change │
│ QQuery 7  │   72.79 ms │                                 73.03 ms │     no change │
│ QQuery 8  │   37.65 ms │                                 36.88 ms │     no change │
│ QQuery 9  │   51.43 ms │                                 52.06 ms │     no change │
│ QQuery 10 │   61.69 ms │                                 61.48 ms │     no change │
│ QQuery 11 │  321.78 ms │                                323.56 ms │     no change │
│ QQuery 12 │   30.62 ms │                                 30.13 ms │     no change │
│ QQuery 13 │  116.96 ms │                                116.41 ms │     no change │
│ QQuery 14 │  397.30 ms │                                390.83 ms │     no change │
│ QQuery 15 │   63.64 ms │                                 62.10 ms │     no change │
│ QQuery 16 │    6.91 ms │                                  5.75 ms │ +1.20x faster │
│ QQuery 17 │   82.26 ms │                                 81.07 ms │     no change │
│ QQuery 18 │  110.93 ms │                                109.86 ms │     no change │
│ QQuery 19 │   42.66 ms │                                 42.21 ms │     no change │
│ QQuery 20 │   38.31 ms │                                 36.82 ms │     no change │
│ QQuery 21 │   17.86 ms │                                 17.91 ms │     no change │
│ QQuery 22 │   71.45 ms │                                 68.67 ms │     no change │
│ QQuery 23 │  334.68 ms │                                324.91 ms │     no change │
│ QQuery 24 │  203.53 ms │                                203.23 ms │     no change │
│ QQuery 25 │  110.79 ms │                                111.25 ms │     no change │
│ QQuery 26 │   47.26 ms │                                 46.94 ms │     no change │
│ QQuery 27 │    6.42 ms │                                  6.28 ms │     no change │
│ QQuery 28 │   62.26 ms │                                 61.00 ms │     no change │
│ QQuery 29 │   97.67 ms │                                 97.65 ms │     no change │
│ QQuery 30 │   35.46 ms │                                 34.68 ms │     no change │
│ QQuery 31 │  112.48 ms │                                111.69 ms │     no change │
│ QQuery 32 │   21.52 ms │                                 21.14 ms │     no change │
│ QQuery 33 │   36.96 ms │                                 37.56 ms │     no change │
│ QQuery 34 │   10.61 ms │                                 10.55 ms │     no change │
│ QQuery 35 │   78.82 ms │                                 76.71 ms │     no change │
│ QQuery 36 │    6.34 ms │                                  6.12 ms │     no change │
│ QQuery 37 │    7.41 ms │                                  7.27 ms │     no change │
│ QQuery 38 │   65.79 ms │                                 64.30 ms │     no change │
│ QQuery 39 │   77.44 ms │                                 77.08 ms │     no change │
│ QQuery 40 │   24.94 ms │                                 25.35 ms │     no change │
│ QQuery 41 │   13.24 ms │                                 13.23 ms │     no change │
│ QQuery 42 │   24.48 ms │                                 24.37 ms │     no change │
│ QQuery 43 │    5.56 ms │                                  5.37 ms │     no change │
│ QQuery 44 │    9.69 ms │                                  9.31 ms │     no change │
│ QQuery 45 │   44.49 ms │                                 42.06 ms │ +1.06x faster │
│ QQuery 46 │   12.61 ms │                                 12.02 ms │     no change │
│ QQuery 47 │  254.85 ms │                                251.01 ms │     no change │
│ QQuery 48 │   92.44 ms │                                 92.45 ms │     no change │
│ QQuery 49 │   70.91 ms │                                 71.63 ms │     no change │
│ QQuery 50 │   59.20 ms │                                 60.64 ms │     no change │
│ QQuery 51 │   94.43 ms │                                 94.21 ms │     no change │
│ QQuery 52 │   24.52 ms │                                 24.45 ms │     no change │
│ QQuery 53 │   29.89 ms │                                 29.63 ms │     no change │
│ QQuery 54 │   54.40 ms │                                 55.36 ms │     no change │
│ QQuery 55 │   24.08 ms │                                 24.53 ms │     no change │
│ QQuery 56 │   38.14 ms │                                 39.34 ms │     no change │
│ QQuery 57 │  175.74 ms │                                176.96 ms │     no change │
│ QQuery 58 │  109.56 ms │                                108.10 ms │     no change │
│ QQuery 59 │  118.72 ms │                                118.25 ms │     no change │
│ QQuery 60 │   39.22 ms │                                 38.47 ms │     no change │
│ QQuery 61 │   11.47 ms │                                 11.06 ms │     no change │
│ QQuery 62 │   45.61 ms │                                 44.62 ms │     no change │
│ QQuery 63 │   30.70 ms │                                 29.84 ms │     no change │
│ QQuery 64 │  382.12 ms │                                378.06 ms │     no change │
│ QQuery 65 │  134.53 ms │                                135.66 ms │     no change │
│ QQuery 66 │   81.57 ms │                                 78.90 ms │     no change │
│ QQuery 67 │  278.86 ms │                                273.26 ms │     no change │
│ QQuery 68 │   12.57 ms │                                 12.19 ms │     no change │
│ QQuery 69 │   58.06 ms │                                 56.32 ms │     no change │
│ QQuery 70 │  105.08 ms │                                108.50 ms │     no change │
│ QQuery 71 │   35.12 ms │                                 35.08 ms │     no change │
│ QQuery 72 │ 1752.61 ms │                               1767.53 ms │     no change │
│ QQuery 73 │   11.08 ms │                                 10.82 ms │     no change │
│ QQuery 74 │  181.96 ms │                                175.91 ms │     no change │
│ QQuery 75 │  145.70 ms │                                142.97 ms │     no change │
│ QQuery 76 │   35.64 ms │                                 35.35 ms │     no change │
│ QQuery 77 │   62.01 ms │                                 60.58 ms │     no change │
│ QQuery 78 │  176.13 ms │                                172.60 ms │     no change │
│ QQuery 79 │   69.51 ms │                                 69.10 ms │     no change │
│ QQuery 80 │   97.89 ms │                                 99.09 ms │     no change │
│ QQuery 81 │   26.94 ms │                                 27.29 ms │     no change │
│ QQuery 82 │   17.74 ms │                                 17.44 ms │     no change │
│ QQuery 83 │   34.33 ms │                                 33.93 ms │     no change │
│ QQuery 84 │   30.52 ms │                                 30.68 ms │     no change │
│ QQuery 85 │  101.40 ms │                                100.67 ms │     no change │
│ QQuery 86 │   26.63 ms │                                 26.44 ms │     no change │
│ QQuery 87 │   65.36 ms │                                 66.12 ms │     no change │
│ QQuery 88 │   60.27 ms │                                 60.34 ms │     no change │
│ QQuery 89 │   35.42 ms │                                 35.78 ms │     no change │
│ QQuery 90 │   16.90 ms │                                 16.79 ms │     no change │
│ QQuery 91 │   42.27 ms │                                 42.22 ms │     no change │
│ QQuery 92 │   30.67 ms │                                 30.82 ms │     no change │
│ QQuery 93 │   52.44 ms │                                 50.99 ms │     no change │
│ QQuery 94 │   39.36 ms │                                 38.83 ms │     no change │
│ QQuery 95 │   81.90 ms │                                 81.02 ms │     no change │
│ QQuery 96 │   24.10 ms │                                 24.19 ms │     no change │
│ QQuery 97 │   52.26 ms │                                 52.34 ms │     no change │
│ QQuery 98 │   45.90 ms │                                 45.76 ms │     no change │
│ QQuery 99 │   67.39 ms │                                 67.10 ms │     no change │
└───────────┴────────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 9431.37ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 9375.86ms │
│ Average Time (HEAD)                                     │   95.27ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │   94.71ms │
│ Queries Faster                                          │         2 │
│ Queries Slower                                          │         0 │
│ Queries with No Change                                  │        97 │
│ Queries with Failure                                    │         0 │
└─────────────────────────────────────────────────────────┴───────────┘

Distribution per query (min / mean ±stddev / max):

Comparing HEAD and fix_single-distinct-groupby-memory-usage
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃ fix_single-distinct-groupby-memory-usage ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │           5.76 / 6.51 ±1.25 / 9.01 ms │              5.61 / 6.28 ±1.02 / 8.31 ms │     no change │
│ QQuery 2  │        83.34 / 84.35 ±1.20 / 86.66 ms │           82.53 / 82.91 ±0.29 / 83.27 ms │     no change │
│ QQuery 3  │        29.31 / 29.46 ±0.14 / 29.63 ms │           28.98 / 29.13 ±0.11 / 29.32 ms │     no change │
│ QQuery 4  │     502.51 / 513.59 ±7.66 / 523.98 ms │        500.69 / 510.80 ±6.18 / 519.55 ms │     no change │
│ QQuery 5  │        52.20 / 52.80 ±0.46 / 53.59 ms │           50.92 / 51.36 ±0.33 / 51.84 ms │     no change │
│ QQuery 6  │        37.43 / 38.04 ±0.41 / 38.66 ms │           37.04 / 37.32 ±0.24 / 37.69 ms │     no change │
│ QQuery 7  │        72.79 / 73.79 ±0.64 / 74.37 ms │           73.03 / 73.81 ±0.48 / 74.52 ms │     no change │
│ QQuery 8  │        37.65 / 38.98 ±2.18 / 43.31 ms │           36.88 / 37.57 ±0.63 / 38.70 ms │     no change │
│ QQuery 9  │        51.43 / 56.48 ±3.88 / 62.96 ms │           52.06 / 53.50 ±1.12 / 54.68 ms │ +1.06x faster │
│ QQuery 10 │        61.69 / 62.23 ±0.49 / 63.15 ms │           61.48 / 61.74 ±0.24 / 62.18 ms │     no change │
│ QQuery 11 │     321.78 / 328.18 ±6.07 / 336.32 ms │        323.56 / 326.71 ±3.21 / 332.68 ms │     no change │
│ QQuery 12 │        30.62 / 31.08 ±0.37 / 31.54 ms │           30.13 / 30.68 ±0.46 / 31.37 ms │     no change │
│ QQuery 13 │     116.96 / 119.23 ±1.29 / 120.95 ms │        116.41 / 117.54 ±0.71 / 118.30 ms │     no change │
│ QQuery 14 │     397.30 / 398.53 ±2.09 / 402.69 ms │        390.83 / 399.46 ±5.41 / 407.34 ms │     no change │
│ QQuery 15 │        63.64 / 65.40 ±2.18 / 69.70 ms │           62.10 / 62.85 ±0.88 / 64.28 ms │     no change │
│ QQuery 16 │           6.91 / 7.05 ±0.16 / 7.33 ms │              5.75 / 5.93 ±0.11 / 6.07 ms │ +1.19x faster │
│ QQuery 17 │        82.26 / 83.66 ±1.49 / 86.32 ms │           81.07 / 82.14 ±1.67 / 85.46 ms │     no change │
│ QQuery 18 │     110.93 / 112.40 ±0.79 / 113.10 ms │        109.86 / 111.17 ±1.25 / 113.36 ms │     no change │
│ QQuery 19 │        42.66 / 42.87 ±0.18 / 43.19 ms │           42.21 / 42.72 ±0.61 / 43.92 ms │     no change │
│ QQuery 20 │        38.31 / 40.11 ±3.04 / 46.16 ms │           36.82 / 38.77 ±1.54 / 41.48 ms │     no change │
│ QQuery 21 │        17.86 / 18.34 ±0.33 / 18.81 ms │           17.91 / 18.06 ±0.17 / 18.40 ms │     no change │
│ QQuery 22 │        71.45 / 72.41 ±1.02 / 73.90 ms │           68.67 / 69.91 ±0.83 / 71.28 ms │     no change │
│ QQuery 23 │     334.68 / 337.16 ±2.62 / 342.04 ms │        324.91 / 335.63 ±6.63 / 342.70 ms │     no change │
│ QQuery 24 │     203.53 / 213.89 ±7.41 / 223.61 ms │        203.23 / 212.19 ±6.51 / 221.49 ms │     no change │
│ QQuery 25 │     110.79 / 113.44 ±2.07 / 117.17 ms │        111.25 / 112.98 ±1.78 / 116.36 ms │     no change │
│ QQuery 26 │        47.26 / 48.84 ±2.14 / 53.03 ms │           46.94 / 49.00 ±2.97 / 54.87 ms │     no change │
│ QQuery 27 │           6.42 / 6.53 ±0.11 / 6.72 ms │              6.28 / 6.43 ±0.10 / 6.54 ms │     no change │
│ QQuery 28 │        62.26 / 63.09 ±0.63 / 64.01 ms │           61.00 / 61.78 ±0.47 / 62.49 ms │     no change │
│ QQuery 29 │       97.67 / 99.13 ±1.36 / 101.19 ms │          97.65 / 99.49 ±1.55 / 101.85 ms │     no change │
│ QQuery 30 │        35.46 / 38.37 ±4.48 / 47.29 ms │           34.68 / 36.58 ±2.98 / 42.51 ms │     no change │
│ QQuery 31 │     112.48 / 113.58 ±0.87 / 114.67 ms │        111.69 / 112.91 ±0.67 / 113.51 ms │     no change │
│ QQuery 32 │        21.52 / 21.74 ±0.20 / 21.99 ms │           21.14 / 21.58 ±0.38 / 22.27 ms │     no change │
│ QQuery 33 │        36.96 / 37.45 ±0.25 / 37.65 ms │           37.56 / 37.86 ±0.32 / 38.34 ms │     no change │
│ QQuery 34 │        10.61 / 12.36 ±3.02 / 18.38 ms │           10.55 / 11.06 ±0.59 / 12.18 ms │ +1.12x faster │
│ QQuery 35 │        78.82 / 79.70 ±0.88 / 81.24 ms │           76.71 / 78.87 ±2.41 / 83.07 ms │     no change │
│ QQuery 36 │           6.34 / 6.48 ±0.14 / 6.72 ms │              6.12 / 6.18 ±0.07 / 6.30 ms │     no change │
│ QQuery 37 │           7.41 / 7.51 ±0.07 / 7.59 ms │              7.27 / 7.45 ±0.16 / 7.69 ms │     no change │
│ QQuery 38 │        65.79 / 67.55 ±1.23 / 69.00 ms │           64.30 / 65.31 ±0.74 / 66.31 ms │     no change │
│ QQuery 39 │        77.44 / 80.02 ±2.65 / 84.87 ms │           77.08 / 78.76 ±1.83 / 81.91 ms │     no change │
│ QQuery 40 │        24.94 / 25.55 ±0.42 / 25.97 ms │           25.35 / 25.68 ±0.33 / 26.17 ms │     no change │
│ QQuery 41 │        13.24 / 13.28 ±0.04 / 13.35 ms │           13.23 / 13.99 ±1.28 / 16.55 ms │  1.05x slower │
│ QQuery 42 │        24.48 / 24.88 ±0.48 / 25.75 ms │           24.37 / 24.84 ±0.54 / 25.83 ms │     no change │
│ QQuery 43 │           5.56 / 5.61 ±0.05 / 5.67 ms │              5.37 / 5.48 ±0.08 / 5.61 ms │     no change │
│ QQuery 44 │          9.69 / 9.91 ±0.17 / 10.11 ms │              9.31 / 9.44 ±0.10 / 9.57 ms │     no change │
│ QQuery 45 │        44.49 / 45.52 ±0.85 / 46.83 ms │           42.06 / 43.48 ±1.33 / 45.96 ms │     no change │
│ QQuery 46 │        12.61 / 12.77 ±0.17 / 13.02 ms │           12.02 / 12.48 ±0.30 / 12.84 ms │     no change │
│ QQuery 47 │     254.85 / 261.77 ±5.99 / 272.95 ms │        251.01 / 253.36 ±2.68 / 258.51 ms │     no change │
│ QQuery 48 │        92.44 / 92.64 ±0.18 / 92.90 ms │           92.45 / 93.91 ±1.22 / 95.57 ms │     no change │
│ QQuery 49 │        70.91 / 72.53 ±1.13 / 74.12 ms │           71.63 / 72.60 ±0.84 / 73.69 ms │     no change │
│ QQuery 50 │        59.20 / 60.51 ±0.85 / 61.88 ms │           60.64 / 62.96 ±3.99 / 70.89 ms │     no change │
│ QQuery 51 │        94.43 / 95.66 ±0.78 / 96.84 ms │          94.21 / 96.98 ±3.05 / 102.89 ms │     no change │
│ QQuery 52 │        24.52 / 25.26 ±0.96 / 27.17 ms │           24.45 / 24.83 ±0.27 / 25.07 ms │     no change │
│ QQuery 53 │        29.89 / 31.93 ±2.97 / 37.79 ms │           29.63 / 29.85 ±0.15 / 30.05 ms │ +1.07x faster │
│ QQuery 54 │        54.40 / 54.77 ±0.45 / 55.63 ms │           55.36 / 57.78 ±4.11 / 65.99 ms │  1.05x slower │
│ QQuery 55 │        24.08 / 24.45 ±0.39 / 25.04 ms │           24.53 / 24.78 ±0.30 / 25.36 ms │     no change │
│ QQuery 56 │        38.14 / 38.58 ±0.37 / 39.07 ms │           39.34 / 39.89 ±0.46 / 40.50 ms │     no change │
│ QQuery 57 │     175.74 / 178.61 ±2.61 / 183.20 ms │        176.96 / 179.00 ±2.06 / 182.96 ms │     no change │
│ QQuery 58 │     109.56 / 111.33 ±1.96 / 114.88 ms │        108.10 / 109.77 ±1.15 / 111.53 ms │     no change │
│ QQuery 59 │     118.72 / 119.92 ±0.65 / 120.71 ms │        118.25 / 120.25 ±1.84 / 123.46 ms │     no change │
│ QQuery 60 │        39.22 / 39.58 ±0.29 / 40.05 ms │           38.47 / 39.33 ±0.65 / 40.36 ms │     no change │
│ QQuery 61 │        11.47 / 11.63 ±0.13 / 11.76 ms │           11.06 / 11.31 ±0.15 / 11.49 ms │     no change │
│ QQuery 62 │        45.61 / 47.46 ±2.02 / 51.10 ms │           44.62 / 46.42 ±2.58 / 51.53 ms │     no change │
│ QQuery 63 │        30.70 / 30.91 ±0.13 / 31.10 ms │           29.84 / 30.50 ±0.42 / 30.99 ms │     no change │
│ QQuery 64 │     382.12 / 384.93 ±1.96 / 388.02 ms │        378.06 / 383.83 ±6.81 / 396.52 ms │     no change │
│ QQuery 65 │     134.53 / 137.91 ±1.99 / 140.28 ms │        135.66 / 138.42 ±2.31 / 142.12 ms │     no change │
│ QQuery 66 │        81.57 / 83.02 ±1.82 / 86.34 ms │           78.90 / 81.26 ±4.02 / 89.27 ms │     no change │
│ QQuery 67 │     278.86 / 283.02 ±2.90 / 287.85 ms │        273.26 / 277.68 ±4.89 / 286.66 ms │     no change │
│ QQuery 68 │        12.57 / 12.78 ±0.16 / 12.99 ms │           12.19 / 12.34 ±0.13 / 12.58 ms │     no change │
│ QQuery 69 │        58.06 / 61.96 ±5.07 / 71.93 ms │           56.32 / 57.26 ±0.57 / 57.98 ms │ +1.08x faster │
│ QQuery 70 │     105.08 / 108.28 ±2.23 / 111.94 ms │        108.50 / 111.39 ±4.02 / 119.21 ms │     no change │
│ QQuery 71 │        35.12 / 35.67 ±0.30 / 36.03 ms │           35.08 / 35.52 ±0.25 / 35.82 ms │     no change │
│ QQuery 72 │ 1752.61 / 1819.02 ±59.84 / 1928.13 ms │    1767.53 / 1799.64 ±36.60 / 1870.08 ms │     no change │
│ QQuery 73 │        11.08 / 12.43 ±2.13 / 16.68 ms │           10.82 / 11.04 ±0.16 / 11.29 ms │ +1.13x faster │
│ QQuery 74 │     181.96 / 186.26 ±3.00 / 190.40 ms │        175.91 / 182.95 ±5.00 / 188.40 ms │     no change │
│ QQuery 75 │     145.70 / 147.82 ±1.97 / 151.50 ms │        142.97 / 147.38 ±3.99 / 154.56 ms │     no change │
│ QQuery 76 │        35.64 / 35.85 ±0.15 / 36.05 ms │           35.35 / 35.97 ±0.46 / 36.48 ms │     no change │
│ QQuery 77 │        62.01 / 64.48 ±4.23 / 72.93 ms │           60.58 / 61.37 ±0.75 / 62.61 ms │     no change │
│ QQuery 78 │     176.13 / 184.00 ±7.14 / 194.93 ms │        172.60 / 177.29 ±5.62 / 188.31 ms │     no change │
│ QQuery 79 │        69.51 / 71.89 ±3.66 / 79.17 ms │           69.10 / 71.87 ±4.50 / 80.81 ms │     no change │
│ QQuery 80 │      97.89 / 100.20 ±2.04 / 103.85 ms │         99.09 / 101.44 ±2.14 / 104.15 ms │     no change │
│ QQuery 81 │        26.94 / 28.52 ±2.68 / 33.86 ms │           27.29 / 27.67 ±0.20 / 27.87 ms │     no change │
│ QQuery 82 │        17.74 / 17.93 ±0.12 / 18.10 ms │           17.44 / 17.77 ±0.31 / 18.14 ms │     no change │
│ QQuery 83 │        34.33 / 35.09 ±0.85 / 36.72 ms │           33.93 / 34.46 ±0.35 / 34.81 ms │     no change │
│ QQuery 84 │        30.52 / 31.91 ±2.13 / 36.14 ms │           30.68 / 32.29 ±2.38 / 37.00 ms │     no change │
│ QQuery 85 │     101.40 / 102.78 ±1.83 / 106.35 ms │        100.67 / 101.56 ±0.95 / 103.27 ms │     no change │
│ QQuery 86 │        26.63 / 27.10 ±0.32 / 27.58 ms │           26.44 / 26.72 ±0.18 / 26.96 ms │     no change │
│ QQuery 87 │        65.36 / 66.81 ±1.05 / 68.43 ms │           66.12 / 66.95 ±0.54 / 67.46 ms │     no change │
│ QQuery 88 │        60.27 / 60.84 ±0.35 / 61.29 ms │           60.34 / 60.81 ±0.35 / 61.21 ms │     no change │
│ QQuery 89 │        35.42 / 35.53 ±0.09 / 35.67 ms │           35.78 / 36.16 ±0.26 / 36.56 ms │     no change │
│ QQuery 90 │        16.90 / 18.35 ±2.75 / 23.85 ms │           16.79 / 16.94 ±0.18 / 17.25 ms │ +1.08x faster │
│ QQuery 91 │        42.27 / 42.57 ±0.35 / 43.22 ms │           42.22 / 42.56 ±0.26 / 42.82 ms │     no change │
│ QQuery 92 │        30.67 / 31.46 ±0.73 / 32.61 ms │           30.82 / 32.84 ±3.94 / 40.72 ms │     no change │
│ QQuery 93 │        52.44 / 53.35 ±0.84 / 54.45 ms │           50.99 / 52.74 ±1.55 / 55.23 ms │     no change │
│ QQuery 94 │        39.36 / 39.98 ±0.35 / 40.43 ms │           38.83 / 39.82 ±0.78 / 40.75 ms │     no change │
│ QQuery 95 │        81.90 / 84.00 ±2.40 / 88.52 ms │           81.02 / 82.16 ±0.85 / 83.12 ms │     no change │
│ QQuery 96 │        24.10 / 24.38 ±0.42 / 25.20 ms │           24.19 / 25.57 ±2.61 / 30.80 ms │     no change │
│ QQuery 97 │        52.26 / 53.11 ±0.69 / 54.11 ms │           52.34 / 53.96 ±1.56 / 55.88 ms │     no change │
│ QQuery 98 │        45.90 / 46.67 ±0.75 / 48.03 ms │           45.76 / 46.13 ±0.49 / 47.04 ms │     no change │
│ QQuery 99 │        67.39 / 68.96 ±1.71 / 72.27 ms │           67.10 / 67.39 ±0.21 / 67.65 ms │     no change │
└───────────┴───────────────────────────────────────┴──────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary                                       ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)                                       │ 9656.23ms │
│ Total Time (fix_single-distinct-groupby-memory-usage)   │ 9564.43ms │
│ Average Time (HEAD)                                     │   97.54ms │
│ Average Time (fix_single-distinct-groupby-memory-usage) │   96.61ms │
│ Queries Faster                                          │         7 │
│ Queries Slower                                          │         2 │
│ Queries with No Change                                  │        90 │
│ Queries with Failure                                    │         0 │
└─────────────────────────────────────────────────────────┴───────────┘

Resource Usage

tpcds — base (merge-base)

Metric Value
Wall time 50.0s
Peak memory 2.4 GiB
Avg memory 1.6 GiB
CPU user 208.1s
CPU sys 6.0s
Peak spill 0 B

tpcds — branch

Metric Value
Wall time 50.0s
Peak memory 2.2 GiB
Avg memory 1.5 GiB
CPU user 207.8s
CPU sys 5.9s
Peak spill 0 B

File an issue against this benchmark runner

@mkleen

mkleen commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

@mohitgurav20 Thanks! Looks good at first glance. I’ll go ahead and start the review.

@mkleen

mkleen commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Great. So in which scenarios would switching of the rewrite makes sense? When does it significantly reduce memory consumption with only a minor impact on performance?

For GROUP BY queries with numeric distincts (e.g. sum(DISTINCT int), avg(DISTINCT float)), skipping the two-phase rewrite reduces peak memory by 60% to 76% (from ~194 MB down to ~46–76 MB) while running at basically the same speed (0.9x–1.1x).

Ok, this is the part i would focus on.

@mohitgurav20

Copy link
Copy Markdown
Contributor Author

From checking the execution plans and benchmark numbers, turning off the rewrite (prefer_memory = true) gives a big advantage mainly in two cases:

  1. GROUP BY queries on numeric data (especially with companion aggregates):
    This showed the biggest memory drop. In queries like SELECT y, sum(y), sum(DISTINCT x) and SELECT y, sum(DISTINCT x), peak memory dropped by 60% to 76% (from around 194 MB down to 46–77 MB), and the runtime was basically identical or even slightly faster (183 ms vs 209 ms).

    The reason is that the 2-phase rewrite creates an extra intermediate aggregate grouped by both (y, x) and shuffles that across partitions. But for numeric types like ints and floats, values are small and fixed-size. With single-phase, we only maintain the y group table and handle distinct values in place, so we completely avoid materializing and shuffling that intermediate (y, x) table.

  2. Low cardinality columns (like smallint or categorical IDs):
    For count(DISTINCT smallint), single-phase was 2.5x faster (2.3 ms vs 5.8 ms) and used 88% less memory (0.07 MB vs 0.57 MB). When there are very few distinct values, setting up a 2-phase aggregation and repartitioning is just extra overhead.

On the other hand, the benchmarks also clearly showed why the rewrite should stay enabled by default:

  • Queries without GROUP BY: Without the rewrite, DataFusion runs the distinct aggregation on a single partition/thread, which causes a 1.6x to 3.4x slowdown on larger datasets.
  • Strings: Storing distinct strings without the early 2-phase reduction causes a lot of heap allocations in the accumulators, which actually increases peak memory (+10% to +45%) and makes it much slower.

So the flag works best when users have memory-heavy GROUP BY queries over numeric or low-cardinality data, where they can save up to ~75% peak memory with almost zero performance impact.

@mkleen

mkleen commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Can we implement the flag in a way, that the memory comsumptions gets better without having any real bad performance impacts and avoid the cases where it gets worse ?

@mohitgurav20

Copy link
Copy Markdown
Contributor Author

Yes, we can definitely do that.

From the benchmarks, the only cases that got worse were:

  1. Queries without GROUP BY (because they lose multi-threading).
  2. String columns (because of per-string memory allocations).

So under the flag, we can only skip the rewrite if:

  • The query has a GROUP BY (!aggr.group_expr.is_empty())
  • The distinct column is a fixed numeric/primitive type (not strings)

That way, strings and queries without GROUP BY will continue using the 2-phase rewrite as normal, and only numeric GROUP BY queries will skip it—giving the 60%–76% memory savings with no real performance hit.

I can push this change if that sounds good to you!

@mkleen

mkleen commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

@mohitgurav20 Thanks i will review it asap.

@mohitgurav20

Copy link
Copy Markdown
Contributor Author

@mkleen yeah sure sir have a look whenever u get time , and feel free to address any changes to be done by my side.

shehabgamin pushed a commit to lakehq/datafusion that referenced this pull request Nov 8, 2026
## Which issue does this PR close?

Closes apache#25936.

## Rationale for this change

Grouped integer `count(DISTINCT x)` can use its native GroupsAccumulator
to avoid an extra aggregate over distinct `(group, value)` pairs. This
helps the original single-target-partition workload, but the choice also
affects spilling and performance on other data shapes.

The native plan is now **opt-in**. The default keeps the existing
two-phase rewrite. Under a 1 MiB memory limit, the reviewer's query with
two groups and 100,000 distinct values completes with the rewrite and
returns `2, 100000`; the native plan runs out of memory. Native DISTINCT
must fit each group's distinct values in memory, including when merging
spilled or partial states.

## What changes are included in this PR?

Add `datafusion.optimizer.single_distinct_prefer_native`, default
`false`. When enabled, grouped all-DISTINCT aggregates retain the native
plan only if:

- `execution.target_partitions == 1`;
- all aggregates share one DISTINCT argument;
- every aggregate explicitly reports specialized GroupsAccumulator
support for its argument types.

Unknown support preserves the rewrite. Integer DISTINCT counts currently
qualify; string and floating-point arguments, global aggregates, mixed
aggregates and multiple target partitions keep their existing behavior.

The earlier [GKE ClickBench
comparison](apache#25988 (comment))
regressed with native parallel plans, so multiple target partitions
continue to distribute deduplication by both the group key and distinct
value.

One target partition can still have multiple input partitions. `UNION
ALL` and a table created with four partitions can use Partial → Coalesce
→ Final and rebuild the DISTINCT set in Final. This is covered by
execution tests and physical-plan snapshots.

Add a ten-query SQL benchmark suite covering argument types,
grouping-key types, cardinality, skew and duplicates. Q10 has one
million groups with four copies of the same value per group at the
default four million rows. Native execution probes both the group table
and the distinct set on every row; the rewrite's outer aggregate only
sees deduplicated pairs. This is an unfavorable case for the native
path, and the logical rule has no statistics to cost it.

This overlaps with the option proposed in apache#26000. `prefer_native`
describes the plan choice without promising lower memory use; the two
PRs should converge on one setting.

### Local comparison, November 7

Compared main `636590b` with review-fix commit `4a0bacd4`, flag off and
on, on Linux (Xeon Gold 6238T, CPU affinity 0–7), Rust 1.99.1,
`release-nonlto`, four million rows, greedy / 1 GiB. All ten queries ran
at 1, 4 and 12 target partitions in three rounds, reversing version
order in the second round. Each round had six iterations per query, with
the first discarded: 15 retained samples per version and configuration.
All result assertions passed. The main executable was reused from the
November 2 build; the review fix was freshly rebuilt, and all versions
used the same updated ten-query suite. No builds ran during timing.

Single-partition medians:

| Case | Main | Flag off (default) | Flag on | On vs off elapsed time |
| --- | ---: | ---: | ---: | ---: |
| Q01: Int64, 2,000 groups, high NDV | 448.97 ms | 424.17 ms | 305.27 ms
| −28.0% |
| Q02: Int64, 2,000 groups, low NDV | 102.96 ms | 101.23 ms | 79.91 ms |
−21.1% |
| Q10: 1M groups, four identical values per group | 316.79 ms | 284.87
ms | 398.12 ms | +39.8% |

Q10 reproduces the reviewer's regression. Its memory-pool peak also
rises from 69.88 MiB with the flag off to 95.88 MiB with it on. Q01 goes
the other way, from 191.45 to 168.17 MiB. Both the runtime and memory
tradeoffs are reasons to keep this opt-in.

The primary comparison is off/on in the same executable. Main and
flag-off use the same plans but have timing differences on this shared
host. At four and twelve target partitions both flag values keep the
rewrite; observed off/on median differences range from −8.0% to +11.2%.
Separate physical-plan checks for Q01 and Q10 passed for all three
versions at all three partition settings (18 checks).

## What is the testing strategy for this PR?

SQL tests cover the default and both flag values in one session, integer
types and NULLs, the low-memory spill reproducer, native plan selection,
`UNION ALL`, a pre-partitioned table, and the rewrite at four target
partitions. The configuration documentation and information-schema
snapshots include the new default.

After syncing with main `4bf32cb4`, formatting, generated configuration
docs, Prettier, strict all-targets/all-features Clippy and the full
`dev/rust_lint.sh` passed on Linux at `0db14a06`. The extended workspace
run passed 13,537 Rust tests (8 ignored, none failed) and all 547 SQL
files. The CLI run passed 116 tests, and the focused SQL run passed all
seven files. The committed PR range also passed the large-file check.

## Are there any user-facing changes?

The new setting lets users opt into native grouped integer DISTINCT
counts with one target partition. Default planning stays unchanged.

---------

Co-authored-by: hushen <190065939+918154429@users.noreply.github.com>
…roupby-memory-usage

# Conflicts:
#	datafusion/common/src/config.rs
#	datafusion/optimizer/src/single_distinct_to_groupby.rs
#	datafusion/sqllogictest/test_files/information_schema.slt
#	docs/source/user-guide/configs.md
@mohitgurav20
mohitgurav20 force-pushed the fix/single-distinct-groupby-memory-usage branch from e3dd29a to c413a0e Compare November 8, 2026 10:55
@mohitgurav20

Copy link
Copy Markdown
Contributor Author

@mkleen gentle reminder sir to review whenever you are free.

@jayzhan211 jayzhan211 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mohitgurav20 Thanks for the updates and the benchmark numbers. Two things block this for me: with the setting on, float DISTINCT returns different results, and #25988 (merged today) already added single_distinct_prefer_native to this rule, so this would be a second setting for the same choice. Details are inline.

@mkleen one question for you: with a memory limit and spilling on, this setting never lowered the limit a query needed in my runs, and at 4 target partitions it raised it 4–12x (numbers in the config.rs comment). It only lowers peak memory when no limit is set. Is that still the case you want the setting for?

Comment on lines +128 to +130
| DataType::Float16
| DataType::Float32
| DataType::Float64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the setting on, float DISTINCT gives different answers: on (0.0, -0.0, 1.5), count(DISTINCT f) goes from 2 to 3 and avg(DISTINCT f) from 0.75 to 0.5. The native accumulators compare raw bits (Hashable in functions-aggregate-common/src/utils.rs), so -0.0 and 0.0 count as two values, while the rewrite's GROUP BY treats them as one. Could you keep floats on the rewrite and add the test below? It fails without this change.

Suggested change
| DataType::Float16
| DataType::Float32
| DataType::Float64
Regression test for single_distinct_to_groupby.slt (place it while the setting is on)
# Float DISTINCT keeps the rewrite: the native accumulator counts -0.0 and 0.0 separately.
statement ok
CREATE TABLE t_prefer_mem_float AS SELECT * FROM (VALUES (1, CAST('0.0' AS DOUBLE)), (1, CAST('-0.0' AS DOUBLE)), (1, CAST('1.5' AS DOUBLE))) AS v(g, f);

query IIR
SELECT g, count(DISTINCT f), avg(DISTINCT f) FROM t_prefer_mem_float GROUP BY g;
----
1 2 0.75

statement ok
DROP TABLE t_prefer_mem_float;

Comment thread datafusion/common/src/config.rs Outdated
Comment on lines +1943 to +1957
/// When `true`, the `SingleDistinctToGroupBy` optimizer rule applies its cost guard
/// universally — including to lone-distinct queries that have no companion non-distinct
/// aggregates. The rewrite is skipped whenever the distinct function already has a
/// native `GroupsAccumulator`, reducing peak memory by avoiding the larger intermediate
/// `(group, distinct value)` result set that the two-phase plan produces.
///
/// The trade-off is reduced parallelism: skipping the rewrite causes the engine to fall
/// back to serial per-group accumulation, which is typically 2–3× slower for queries
/// with high-cardinality distinct values.
///
/// When `false` (the default), lone-distinct queries are always rewritten into the
/// two-phase `GROUP BY` so they can fan out across partitions and achieve maximum
/// throughput.
///
/// See <https://github.com/apache/datafusion/issues/25932>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under a memory limit, this setting needs more memory, not less: at 4 target partitions, sum(DISTINCT x) on the #25932 table needs 16M with the setting on and finishes within 4M without it (count: 48M vs 4M). The rewrite can spill its (group, value) pairs, but the native accumulator keeps each group's distinct values in memory, so with a few large groups it fails where the default finishes. Your numbers are right for a pool with no limit, so the doc should say that:

Suggested change
/// When `true`, the `SingleDistinctToGroupBy` optimizer rule applies its cost guard
/// universally — including to lone-distinct queries that have no companion non-distinct
/// aggregates. The rewrite is skipped whenever the distinct function already has a
/// native `GroupsAccumulator`, reducing peak memory by avoiding the larger intermediate
/// `(group, distinct value)` result set that the two-phase plan produces.
///
/// The trade-off is reduced parallelism: skipping the rewrite causes the engine to fall
/// back to serial per-group accumulation, which is typically 2–3× slower for queries
/// with high-cardinality distinct values.
///
/// When `false` (the default), lone-distinct queries are always rewritten into the
/// two-phase `GROUP BY` so they can fan out across partitions and achieve maximum
/// throughput.
///
/// See <https://github.com/apache/datafusion/issues/25932>
/// When `true`, the `SingleDistinctToGroupBy` optimizer rule keeps a grouped
/// DISTINCT aggregate native, instead of rewriting it into a two-phase `GROUP BY`,
/// when every DISTINCT argument is a fixed-width, non-float type. This lowers peak
/// memory when no memory limit is set, because the intermediate
/// `(group, distinct value)` result is never built.
///
/// Under a memory limit, the rewrite can spill those pairs, but the native
/// accumulator keeps each group's distinct values in memory. With this option
/// enabled, a query can need more memory, or fail where the rewrite finishes.
///
/// Queries without `GROUP BY`, and other argument types, keep the rewrite.
///
/// See <https://github.com/apache/datafusion/issues/25932>
Smallest memory limit that finishes (release datafusion-cli, greedy pool, spilling on)
query on the #25932 table (4M rows, 2,000 groups) target partitions setting off setting on
sum(DISTINCT x) 1 ≤4M ≤4M (also 1M)
sum(DISTINCT x) 4 ≤4M 16M
count(DISTINCT x) 1 ≤4M ≤4M
count(DISTINCT x) 4 ≤4M 48M

Two large groups at a 1M limit (SELECT v % 2, count(DISTINCT v) FROM generate_series(1, 100000) AS t(v) GROUP BY v % 2, batch_size = 128): the setting fails with Resources exhausted at 1 target partition for count and sum, and at 4 for count. The default finishes in every case. The same query is in aggregate_memory_spill.slt.

configs.md and information_schema.slt need regenerating afterwards.

Comment thread datafusion/common/src/config.rs Outdated
/// throughput.
///
/// See <https://github.com/apache/datafusion/issues/25932>
pub single_distinct_aggregation_prefer_memory: bool, default = false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#25988 (merged today, not released yet) added single_distinct_prefer_native just below for the same choice, and with both settings count(DISTINCT int) at one target partition skips the rewrite under either one. Could this PR widen that setting's gate instead of adding a second setting? Because it hasn't been released, its name and doc can still change, and users would get one switch for "keep grouped DISTINCT native".

Comment on lines +200 to +207
// Aggregates with DistinctHandling::Unsupported (e.g. approx_median) cannot
// run natively with DISTINCT; they must always be rewritten.
if distinct_aggs
.iter()
.any(|(func, _)| func.distinct_handling() == DistinctHandling::Unsupported)
{
return Ok(true);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the setting off, this return also changes main's behavior: SELECT g, count(*), stddev(DISTINCT x) FROM t GROUP BY g fails on main with STDDEV_POP(DISTINCT) aggregations are not available and returns the right rows here. That's a fix, but no test covers it at the default, and the description says the default is unchanged. Could you add this test before the SET … = true line in single_distinct_to_groupby.slt and mention the fix in the description?

# stddev cannot run DISTINCT itself, so it is rewritten even next to count(*).
query IIR rowsort
SELECT g, count(*), stddev(DISTINCT x) FROM t_prefer_mem GROUP BY g;
----
1 2 7.071067811865
2 1 NULL

Comment on lines +236 to +244
// Resolve the data type of each distinct argument.
let all_fixed_width = distinct_aggs.iter().all(|(_, args)| {
args.iter().all(|arg| {
arg.get_type(input_schema)
.map(|dt| is_fixed_width_type(&dt))
.unwrap_or(false)
})
});
if all_fixed_width {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional cleanup: .unwrap_or(false) silently keeps the rewrite when a type can't be resolved, while distinct_groups_support above returns the error with ?. This does the same with one pass:

Suggested change
// Resolve the data type of each distinct argument.
let all_fixed_width = distinct_aggs.iter().all(|(_, args)| {
args.iter().all(|arg| {
arg.get_type(input_schema)
.map(|dt| is_fixed_width_type(&dt))
.unwrap_or(false)
})
});
if all_fixed_width {
let arg_types = distinct_aggs
.iter()
.flat_map(|(_, args)| args.iter())
.map(|arg| arg.get_type(input_schema))
.collect::<Result<Vec<_>>>()?;
if arg_types.iter().all(is_fixed_width_type) {

@mohitgurav20

Copy link
Copy Markdown
Contributor Author

Yeah that's a legit bug, thanks for catching it. The problem is is_fixed_width_type was lumping floats in with integers, which breaks down because the two codepaths disagree on -0.0/0.0 — GROUP BY treats them equal (IEEE 754), but the native accumulator hashes raw bits so they end up in separate buckets. Net result: count(DISTINCT f) changes from 2 to 3 on your example, which is wrong.

Pulled floats out of is_fixed_width_type so prefer_memory never skips the rewrite for float columns. Added a plan-level unit test confirming the rewrite still fires with prefer_memory=true on a Float64 column, and the .slt test with (0.0, -0.0, 1.5) verifying the count stays at 2 under both settings.

On the config overlap with #25988 — makes sense to let @mkleen weigh in first before I touch that. If the consensus is to fold both into one knob I'm happy to do that in a follow-up.

@mohitgurav20

Copy link
Copy Markdown
Contributor Author

@mkleen @jayzhan211 i have worked on it according to the changes you said . pls feel free to review and suggest for any changes .

@mkleen

mkleen commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

@mkleen one question for you: with a memory limit and spilling on, this setting never lowered the limit a query needed in my runs, and at 4 target partitions it raised it 4–12x (numbers in the config.rs comment). It only lowers peak memory when no limit is set. Is that still the case you want the setting for?

@jayzhan211 Yes, the idea was have an option to prefer memory-consumption-over-performance without setting a memory-limit.

@mkleen

mkleen commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

On the config overlap with #25988 — makes sense to let @mkleen weigh in first before I touch that. If the consensus is to fold both into one knob I'm happy to do that in a follow-up.

The config overlap with single_distinct_prefer_native is there. I like the idea to fold both into one setting.

@mohitgurav20

Copy link
Copy Markdown
Contributor Author

@mkleen @jayzhan211 Done — consolidated everything into single_distinct_prefer_native and dropped single_distinct_aggregation_prefer_memory.

Grouped all-distinct queries on fixed-width, non-float types (including sum(DISTINCT int)) now stay native at target_partitions = 1. Multi-partition runs, floats (-0.0 == 0.0), strings, un-grouped queries, and unsupported functions like stddev still rewrite. Docs, schema, and sqllogictests are all updated to match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

common Related to common crate documentation Improvements or additions to documentation optimizer Optimizer rules sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sum(DISTINCT x) with GROUP BY uses twice the memory or more

6 participants