Skip to content

perf: optimizing take_n for DictionaryGroupValuesColumn - #24476

Draft
saadtajwar wants to merge 5 commits into
apache:mainfrom
saadtajwar:saadtajwar/DictionaryGroupValuesColumn-take-n-optimization
Draft

saadtajwar wants to merge 5 commits into
apache:mainfrom
saadtajwar:saadtajwar/DictionaryGroupValuesColumn-take-n-optimization

Conversation

@saadtajwar

@saadtajwar saadtajwar commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change (copied from issue)

DictionaryGroupValuesColumn::take_n emits the first n groups and rebuilds the remainder in-place. Every call hashes all surviving distinct values from scratch to reconstruct value_dedup, making repeated partial emissions O(G² / batch_size) over the lifetime of a query, where G is the total number of distinct values seen. Additionally, arrow::compute::take does not compact the backing storage for Utf8View, BinaryView, or nested dictionary value arrays; the rebuilt column retains a reference to the full original allocation rather than releasing memory proportional to the dropped groups. Under a high-cardinality dictionary key with frequent spill-driven partial emissions (e.g. streaming aggregation with a large fan-out), this combination causes both CPU and peak RSS to grow super-linearly with group count.

What changes are included in this PR?

  • Compact backing storage for rebuilt column
  • Updating value_dedup to only remove/move relevant slots instead of complete rebuild
  • Only adding leftover values to inner for the remainder loop

Are these changes tested?

Yes

Are there any user-facing changes?

No

@github-actions github-actions Bot added the physical-plan Changes to the physical-plan crate label Aug 19, 2026
@codecov-commenter

codecov-commenter commented Aug 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.79518% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81.45%. Comparing base (d1fe988) to head (57131f2).
⚠️ Report is 868 commits behind head on main.

Files with missing lines Patch % Lines
...gregates/group_values/multi_group_by/dictionary.rs 98.78% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #24476   +/-   ##
=======================================
  Coverage   81.45%   81.45%           
=======================================
  Files        1119     1119           
  Lines      400421   400491   +70     
  Branches   400421   400491   +70     
=======================================
+ Hits       326159   326218   +59     
- Misses      55184    55192    +8     
- Partials    19078    19081    +3     

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

@saadtajwar
saadtajwar marked this pull request as ready for review August 20, 2026 15:40
@saadtajwar

Copy link
Copy Markdown
Contributor Author

@Rich-T-kid & @kumarUjjawal - ready for review! Thanks in advance for your feedback!

@saadtajwar saadtajwar changed the title perf: optimizing take_n for DictionaryGroupValuesColumn (DRAFT) perf: optimizing take_n for DictionaryGroupValuesColumn Aug 20, 2026
@Rich-T-kid

Copy link
Copy Markdown
Contributor

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5358284067-1812-nfjkb 6.12.85+ #1 SMP Sat Jun 27 09:31:30 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 saadtajwar/DictionaryGroupValuesColumn-take-n-optimization (901e301) to dbdc627 (merge-base) diff

Run configuration
run benchmark dictionary_group_values

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 saadtajwar/DictionaryGroupValuesColumn-take-n-optimization (901e301) to dbdc627 (merge-base) diff

Run configuration
run benchmark dictionary_group_values
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

group                                                                             HEAD                                    saadtajwar_DictionaryGroupValuesColumn-take-n-optimization
-----                                                                             ----                                    ----------------------------------------------------------
dict_intern_emit/intern_emit/size_65536_card_1000_null_0.00                       1.00    501.1±5.79µs 124.7 MElem/sec    1.01    506.2±5.87µs 123.5 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_20_null_0.00                         1.00    422.5±6.12µs 147.9 MElem/sec    1.01    425.2±6.79µs 147.0 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_300_null_0.00                        1.00    454.4±5.66µs 137.6 MElem/sec    1.01    460.0±6.43µs 135.9 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_65536_null_0.00                      1.00      6.2±0.01ms 10.1 MElem/sec     1.02      6.3±0.01ms  9.9 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_75_null_0.00                         1.00    443.7±5.83µs 140.9 MElem/sec    1.01    446.8±6.24µs 139.9 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_1000_null_0.00                        1.00    126.0±9.63µs 62.0 MElem/sec     1.01    127.4±1.79µs 61.3 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_20_null_0.00                          1.01     58.0±1.08µs 134.8 MElem/sec    1.00     57.3±0.82µs 136.3 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_300_null_0.00                         1.00     77.5±5.36µs 100.8 MElem/sec    1.01     78.0±0.72µs 100.2 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_75_null_0.00                          1.00     63.1±0.63µs 123.7 MElem/sec    1.01     63.5±0.68µs 123.0 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_8192_null_0.00                        1.00    523.7±2.29µs 14.9 MElem/sec     1.02    532.7±1.53µs 14.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_1000_null_0.10     1.00      2.4±0.00ms 105.2 MElem/sec    1.00      2.4±0.01ms 104.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_20_null_0.10       1.01      2.2±0.01ms 112.4 MElem/sec    1.00      2.2±0.01ms 112.9 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_300_null_0.10      1.00      2.3±0.00ms 108.5 MElem/sec    1.00      2.3±0.01ms 108.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_65536_null_0.10    1.01     17.2±0.18ms 14.6 MElem/sec     1.00     17.0±0.17ms 14.7 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_75_null_0.10       1.00      2.3±0.00ms 108.9 MElem/sec    1.00      2.3±0.01ms 108.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_1000_null_0.10      1.01    403.1±1.21µs 77.5 MElem/sec     1.00    398.3±2.11µs 78.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_20_null_0.10        1.04    271.1±2.34µs 115.3 MElem/sec    1.00    261.6±1.98µs 119.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_300_null_0.10       1.02    313.0±1.57µs 99.8 MElem/sec     1.00    307.6±1.89µs 101.6 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_75_null_0.10        1.03    285.4±1.61µs 109.5 MElem/sec    1.00    277.5±1.74µs 112.6 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_8192_null_0.10      1.00   1229.0±4.37µs 25.4 MElem/sec     1.01   1238.8±4.94µs 25.2 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_1000_null_0.10       1.00   1435.1±3.65µs 43.6 MElem/sec     1.00   1437.4±3.99µs 43.5 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_20_null_0.10         1.00   1224.0±3.29µs 51.1 MElem/sec     1.00   1223.2±4.39µs 51.1 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_300_null_0.10        1.00   1283.5±3.17µs 48.7 MElem/sec     1.02   1313.7±3.60µs 47.6 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_65536_null_0.10      1.00     13.9±0.24ms  4.5 MElem/sec     1.00     13.9±0.10ms  4.5 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_75_null_0.10         1.00   1248.4±3.24µs 50.1 MElem/sec     1.00   1246.0±2.96µs 50.2 MElem/sec
dict_take_n/take_n/size_65536_card_1000_null_0.10                                 1.03      2.6±0.00ms 97.7 MElem/sec     1.00      2.5±0.00ms 100.2 MElem/sec
dict_take_n/take_n/size_65536_card_20_null_0.10                                   1.03      2.2±0.01ms 113.5 MElem/sec    1.00      2.1±0.00ms 117.0 MElem/sec
dict_take_n/take_n/size_65536_card_300_null_0.10                                  1.02      2.3±0.00ms 107.1 MElem/sec    1.00      2.3±0.00ms 109.0 MElem/sec
dict_take_n/take_n/size_65536_card_65536_null_0.10                                1.00     25.5±0.07ms  9.8 MElem/sec     1.04     26.4±0.13ms  9.5 MElem/sec
dict_take_n/take_n/size_65536_card_75_null_0.10                                   1.02      2.3±0.01ms 109.8 MElem/sec    1.00      2.2±0.00ms 112.4 MElem/sec

Resource Usage

dictionary_group_values — base (merge-base)

Metric Value
Wall time 405.1s
Peak memory 497.4 MiB
Avg memory 87.3 MiB
CPU user 348.5s
CPU sys 21.7s
Peak spill 0 B

dictionary_group_values — branch

Metric Value
Wall time 465.1s
Peak memory 811.0 MiB
Avg memory 145.7 MiB
CPU user 362.0s
CPU sys 17.2s
Peak spill 0 B

File an issue against this benchmark runner

@Rich-T-kid

Copy link
Copy Markdown
Contributor
dict_take_n/take_n/size_65536_card_1000_null_0.10                                 1.03      2.6±0.00ms 97.7 MElem/sec     1.00      2.5±0.00ms 100.2 MElem/sec
dict_take_n/take_n/size_65536_card_20_null_0.10                                   1.03      2.2±0.01ms 113.5 MElem/sec    1.00      2.1±0.00ms 117.0 MElem/sec
dict_take_n/take_n/size_65536_card_300_null_0.10                                  1.02      2.3±0.00ms 107.1 MElem/sec    1.00      2.3±0.00ms 109.0 MElem/sec
dict_take_n/take_n/size_65536_card_65536_null_0.10                                1.00     25.5±0.07ms  9.8 MElem/sec     1.04     26.4±0.13ms  9.5 MElem/sec
dict_take_n/take_n/size_65536_card_75_null_0.10                                   1.02      2.3±0.01ms 109.8 MElem/sec    1.00      2.2±0.00ms 112.4 MElem/sec

@saadtajwar

@saadtajwar

Copy link
Copy Markdown
Contributor Author
dict_take_n/take_n/size_65536_card_1000_null_0.10                                 1.03      2.6±0.00ms 97.7 MElem/sec     1.00      2.5±0.00ms 100.2 MElem/sec
dict_take_n/take_n/size_65536_card_20_null_0.10                                   1.03      2.2±0.01ms 113.5 MElem/sec    1.00      2.1±0.00ms 117.0 MElem/sec
dict_take_n/take_n/size_65536_card_300_null_0.10                                  1.02      2.3±0.00ms 107.1 MElem/sec    1.00      2.3±0.00ms 109.0 MElem/sec
dict_take_n/take_n/size_65536_card_65536_null_0.10                                1.00     25.5±0.07ms  9.8 MElem/sec     1.04     26.4±0.13ms  9.5 MElem/sec
dict_take_n/take_n/size_65536_card_75_null_0.10                                   1.02      2.3±0.01ms 109.8 MElem/sec    1.00      2.2±0.00ms 112.4 MElem/sec

@saadtajwar

Oof, if I'm reading this correctly this doesn't look like a huge win for us here...any thoughts on how we want move forward here? I feel like we could either:

  • decide the current benchmarks capture the common use cases and don't warrant these changes
  • decide the current benchmarks capture the common use cases and still warrant changes but maybe not the specific changes we have - we could look at the actual change set and either modify or more likely remove some of these optimizations
  • decide to modify the benchmarks to try and better exercise the paths that our current changes would optimize for (maybe increase the number of emit cycles to be >>> 4/5, use more distinct leftovers, use more expensive values with longer strings/Utf8View)

My preference would be the last option, but I'm obviously biased in wanting to see these changes move the needle 😆 open to any feedback!

@Rich-T-kid

Copy link
Copy Markdown
Contributor

the current take_n benchmarks cover the extreme case of a streaming aggregations, emitting half of your input repeatedly. this makes them sensitive to any performance changes we make which is what we want. I'll try and take a look at your PR to see any perf boost we can make

@kumarUjjawal kumarUjjawal 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.

Thank you @saadtajwar for working on this. I have left few comments for you.

Also could you add some tests for these code changes.

@saadtajwar

Copy link
Copy Markdown
Contributor Author

Thank you @saadtajwar for working on this. I have left few comments for you.

Also could you add some tests for these code changes.

Thanks @kumarUjjawal ! Will take a look through these and make changes to address over the next week!

Keep both slot_hash (take_n) and cached_values (append_val hash reuse).
@saadtajwar

Copy link
Copy Markdown
Contributor Author

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

Hi @saadtajwar, thanks for the request (#24476 (comment)). Only whitelisted users can trigger benchmarks. Allowed users: 2010YOUY01, Dandandan, Fokko, Jefffrey, Omega359, Rachelint, Rich-T-kid, adriangb, alamb, asubiotto, avantgardnerio, brunal, buraksenn, cetra3, codephage2020, coderfender, comphead, erenavsarogullari, etseidl, friendlymatthew, gabotechs, geoffreyclaude, grtlr, haohuaijin, jonathanc-n, kevinjqliu, klion26, kosiew, kumarUjjawal, kunalsinghdadhwal, liamzwbao, mbutrovich, mkleen, mzabaluev, neilconway, rluvaton, sdf-jkl, timsaucer, xudong963, zhuqi-lucas.


File an issue against this benchmark runner

@saadtajwar

Copy link
Copy Markdown
Contributor Author

@kumarUjjawal thanks for the review as always! Pushed a commit to address your changes - please let me know your thoughts - curious to see if this made any improvements wrt the benchmark 👀

@Rich-T-kid

Copy link
Copy Markdown
Contributor

run benchmark dictionary_group_values

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c5433231973-2004-8tsz2 6.12.85+ #1 SMP Sat Jun 27 09:31:30 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 saadtajwar/DictionaryGroupValuesColumn-take-n-optimization (57131f2) to d1fe988 (merge-base) diff

Run configuration
run benchmark dictionary_group_values

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 saadtajwar/DictionaryGroupValuesColumn-take-n-optimization (57131f2) to d1fe988 (merge-base) diff

Run configuration
run benchmark dictionary_group_values
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

group                                                                             HEAD                                    saadtajwar_DictionaryGroupValuesColumn-take-n-optimization
-----                                                                             ----                                    ----------------------------------------------------------
dict_intern_emit/intern_emit/size_65536_card_1000_null_0.00                       1.00    496.8±3.06µs 125.8 MElem/sec    1.00    498.3±3.73µs 125.4 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_20_null_0.00                         1.00    421.2±4.43µs 148.4 MElem/sec    1.00    420.3±6.14µs 148.7 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_300_null_0.00                        1.00    451.2±4.22µs 138.5 MElem/sec    1.00    450.4±4.36µs 138.8 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_65536_null_0.00                      1.00      6.2±0.03ms 10.1 MElem/sec     1.03      6.3±0.01ms  9.9 MElem/sec
dict_intern_emit/intern_emit/size_65536_card_75_null_0.00                         1.00    441.6±5.12µs 141.5 MElem/sec    1.00    440.7±4.97µs 141.8 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_1000_null_0.00                        1.00    125.2±6.21µs 62.4 MElem/sec     1.01    127.1±1.02µs 61.5 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_20_null_0.00                          1.00     56.2±0.44µs 139.0 MElem/sec    1.01     56.7±0.53µs 137.8 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_300_null_0.00                         1.00     76.7±0.72µs 101.8 MElem/sec    1.01     77.6±0.60µs 100.7 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_75_null_0.00                          1.00     62.7±0.61µs 124.5 MElem/sec    1.00     62.8±0.51µs 124.4 MElem/sec
dict_intern_emit/intern_emit/size_8192_card_8192_null_0.00                        1.00    521.6±2.28µs 15.0 MElem/sec     1.01    529.1±2.43µs 14.8 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_1000_null_0.10     1.00      2.4±0.01ms 105.5 MElem/sec    1.00      2.4±0.00ms 105.4 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_20_null_0.10       1.00      2.2±0.01ms 113.2 MElem/sec    1.00      2.2±0.00ms 113.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_300_null_0.10      1.00      2.3±0.01ms 108.7 MElem/sec    1.00      2.3±0.01ms 108.2 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_65536_null_0.10    1.03     16.8±0.08ms 14.9 MElem/sec     1.00     16.3±0.07ms 15.4 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_65536_card_75_null_0.10       1.00      2.3±0.01ms 109.4 MElem/sec    1.00      2.3±0.00ms 109.3 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_1000_null_0.10      1.00    399.7±1.45µs 78.2 MElem/sec     1.02    408.4±1.58µs 76.5 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_20_null_0.10        1.00    266.7±1.57µs 117.2 MElem/sec    1.03    274.2±2.31µs 114.0 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_300_null_0.10       1.00    309.8±2.28µs 100.9 MElem/sec    1.11  342.4±258.97µs 91.3 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_75_null_0.10        1.03  298.1±161.23µs 104.8 MElem/sec    1.00    289.6±1.68µs 107.9 MElem/sec
dict_repeated_intern_emit/repeated_intern_emit/size_8192_card_8192_null_0.10      1.00   1235.3±8.83µs 25.3 MElem/sec     1.00   1240.5±5.04µs 25.2 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_1000_null_0.10       1.01   1360.1±5.26µs 46.0 MElem/sec     1.00   1350.5±3.34µs 46.3 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_20_null_0.10         1.01   1232.8±3.36µs 50.7 MElem/sec     1.00   1222.0±2.67µs 51.1 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_300_null_0.10        1.01   1308.7±4.86µs 47.8 MElem/sec     1.00   1293.2±3.60µs 48.3 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_65536_null_0.10      1.00      7.2±0.02ms  8.7 MElem/sec     1.01      7.3±0.03ms  8.6 MElem/sec
dict_scalar_append_equal/scalar_append_equal/size_65536_card_75_null_0.10         1.03   1286.9±2.90µs 48.6 MElem/sec     1.00   1245.1±3.80µs 50.2 MElem/sec
dict_take_n/take_n/size_65536_card_1000_null_0.10                                 1.01      2.5±0.01ms 98.2 MElem/sec     1.00      2.5±0.06ms 99.2 MElem/sec
dict_take_n/take_n/size_65536_card_20_null_0.10                                   1.00      2.2±0.00ms 115.6 MElem/sec    1.01      2.2±0.00ms 114.1 MElem/sec
dict_take_n/take_n/size_65536_card_300_null_0.10                                  1.00      2.3±0.00ms 108.1 MElem/sec    1.01      2.3±0.00ms 106.9 MElem/sec
dict_take_n/take_n/size_65536_card_65536_null_0.10                                1.11     25.8±0.11ms  9.7 MElem/sec     1.00     23.2±0.05ms 10.8 MElem/sec
dict_take_n/take_n/size_65536_card_75_null_0.10                                   1.00      2.2±0.00ms 111.1 MElem/sec    1.02      2.3±0.00ms 109.5 MElem/sec

Resource Usage

dictionary_group_values — base (merge-base)

Metric Value
Wall time 570.1s
Peak memory 734.3 MiB
Avg memory 63.4 MiB
CPU user 347.2s
CPU sys 22.6s
Peak spill 0 B

dictionary_group_values — branch

Metric Value
Wall time 570.1s
Peak memory 842.0 MiB
Avg memory 61.4 MiB
CPU user 351.0s
CPU sys 22.0s
Peak spill 0 B

File an issue against this benchmark runner

}

#[test]
fn take_n_utf8_view_emits_and_interns_leftover_values() {

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.

This test passes when you delete the gc_array call. It asserts on values and on equality, and gc() changes only the buffer layout, not the data. The three strings also hold about 60 bytes of
non-inline data. should_gc_view_array needs more than 10 KB, so the compaction never runs here. Could the test build enough non-inline data to pass that limit, then assert on
get_buffer_memory_size() of the emitted array?

let compact_emit_values =
take(&*all_inner_values, &emit_indices, None).expect("take emit values");
// take() keeps original view buffers while spill's gc_array copies only when worth it
let gced_compact_emit_values = gc_array(&compact_emit_values)

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.

Would it work to add a case with Utf8View values longer than twelve bytes, and enough of them to pass the 10 KB limit?

let leftover_non_null_len = new_to_old.len() - null_old_slot.is_some() as usize;
let old_hashes = std::mem::take(&mut self.slot_hash);
// Remapping entries from current slot
self.value_dedup.retain(|(_, slot)| {

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.

would a shrink_to_fit help here, with the accounting corrected to match?

@Rich-T-kid

Copy link
Copy Markdown
Contributor

@saadtajwar are you still working on this? no rush just checking

@saadtajwar

Copy link
Copy Markdown
Contributor Author

@saadtajwar are you still working on this? no rush just checking

Hey @Rich-T-kid , apologies for the super delayed response - unfortunately I've had to take a step back from contributing recently. If anyone else is wanting to work on this/take it to the finish line please feel free to! Hopefully I can get back to DF contributing in the future :)

@github-actions
github-actions Bot marked this pull request as draft November 9, 2026 01:09
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown

Marked as draft after 14 days without activity: merge conflicts.

Please address these items and mark Ready for review when ready.

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

Labels

physical-plan Changes to the physical-plan crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optimize take_n on DictionaryGroupValuesColumn<K>

5 participants