Skip to content

chore: add utf8 vs Intl.Collator benchmark#5665

Draft
arv wants to merge 2 commits intomainfrom
arv/collator-exploration
Draft

chore: add utf8 vs Intl.Collator benchmark#5665
arv wants to merge 2 commits intomainfrom
arv/collator-exploration

Conversation

@arv
Copy link
Contributor

@arv arv commented Mar 18, 2026

Benchmarks compare-utf8 against Intl.Collator and the JS < operator, covering both correctness (cases where sort order differs) and performance. Motivated by PR #5663 removing COLLATE "ucs_basic".

Benchmarks compare-utf8 against Intl.Collator and the JS < operator,
covering both correctness (cases where sort order differs) and
performance. Motivated by PR #5663 removing COLLATE "ucs_basic".
@arv arv requested review from grgbkr and tantaman March 18, 2026 17:31
@vercel
Copy link

vercel bot commented Mar 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
replicache-docs Ready Ready Preview, Comment Mar 18, 2026 5:42pm
zbugs Ready Ready Preview Mar 18, 2026 5:42pm

Request Review

@github-actions
Copy link

github-actions bot commented Mar 18, 2026

🐰 Bencher Report

Brancharv/collator-exploration
TestbedLinux
Click to view all benchmark results
BenchmarkFile SizeBenchmark Result
kilobytes (KB)
(Result Δ%)
Upper Boundary
kilobytes (KB)
(Limit %)
zero-package.tgz📈 view plot
🚷 view threshold
1,924.12 KB
(+0.04%)Baseline: 1,923.31 KB
1,961.78 KB
(98.08%)
zero.js📈 view plot
🚷 view threshold
278.62 KB
(0.00%)Baseline: 278.62 KB
284.20 KB
(98.04%)
zero.js.br📈 view plot
🚷 view threshold
73.97 KB
(0.00%)Baseline: 73.97 KB
75.45 KB
(98.04%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link

github-actions bot commented Mar 18, 2026

🐰 Bencher Report

Brancharv/collator-exploration
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
1 exists: track.exists(album)📈 view plot
🚷 view threshold
12,817.61 ops/s
(+0.16%)Baseline: 12,797.51 ops/s
11,905.35 ops/s
(92.88%)
10 exists (AND)📈 view plot
🚷 view threshold
182,901.69 ops/s
(-1.25%)Baseline: 185,224.33 ops/s
168,174.36 ops/s
(91.95%)
10 exists (OR)📈 view plot
🚷 view threshold
3,556.23 ops/s
(-4.01%)Baseline: 3,704.95 ops/s
3,475.75 ops/s
(97.74%)
12 exists (AND)📈 view plot
🚷 view threshold
162,454.65 ops/s
(-0.96%)Baseline: 164,027.07 ops/s
149,087.67 ops/s
(91.77%)
12 exists (OR)📈 view plot
🚷 view threshold
3,081.52 ops/s
(-1.75%)Baseline: 3,136.25 ops/s
2,943.59 ops/s
(95.52%)
12 level nesting📈 view plot
🚷 view threshold
2,753.81 ops/s
(+1.34%)Baseline: 2,717.53 ops/s
2,541.87 ops/s
(92.30%)
2 exists (AND): track.exists(album).exists(genre)📈 view plot
🚷 view threshold
4,936.62 ops/s
(+2.20%)Baseline: 4,830.40 ops/s
4,528.97 ops/s
(91.74%)
3 exists (AND)📈 view plot
🚷 view threshold
1,860.78 ops/s
(-1.49%)Baseline: 1,888.98 ops/s
1,765.94 ops/s
(94.90%)
3 exists (OR)📈 view plot
🚷 view threshold
919.40 ops/s
(-2.13%)Baseline: 939.44 ops/s
874.28 ops/s
(95.09%)
5 exists (AND)📈 view plot
🚷 view threshold
291.18 ops/s
(-1.86%)Baseline: 296.71 ops/s
276.56 ops/s
(94.98%)
5 exists (OR)📈 view plot
🚷 view threshold
152.00 ops/s
(-2.89%)Baseline: 156.52 ops/s
145.39 ops/s
(95.65%)
Nested 2 levels: track > album > artist📈 view plot
🚷 view threshold
4,111.66 ops/s
(-2.69%)Baseline: 4,225.17 ops/s
3,932.41 ops/s
(95.64%)
Nested 4 levels: playlist > tracks > album > artist📈 view plot
🚷 view threshold
693.44 ops/s
(+0.98%)Baseline: 686.70 ops/s
640.68 ops/s
(92.39%)
Nested with filters: track > album > artist (filtered)📈 view plot
🚷 view threshold
3,497.84 ops/s
(+0.65%)Baseline: 3,475.19 ops/s
3,235.99 ops/s
(92.51%)
planned: playlist.exists(tracks)📈 view plot
🚷 view threshold
558.17 ops/s
(+17.15%)Baseline: 476.47 ops/s
141.72 ops/s
(25.39%)
planned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
144.11 ops/s
(+2.33%)Baseline: 140.83 ops/s
112.16 ops/s
(77.83%)
planned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
6,837.91 ops/s
(+1.19%)Baseline: 6,757.79 ops/s
5,998.45 ops/s
(87.72%)
planned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
35.14 ops/s
(+24.16%)Baseline: 28.30 ops/s
-2.40 ops/s
(-6.83%)
planned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
4,720.99 ops/s
(+16.71%)Baseline: 4,045.14 ops/s
948.05 ops/s
(20.08%)
planned: track.exists(playlists)📈 view plot
🚷 view threshold
3.62 ops/s
(+16.91%)Baseline: 3.10 ops/s
0.86 ops/s
(23.88%)
unplanned: playlist.exists(tracks)📈 view plot
🚷 view threshold
529.63 ops/s
(+14.32%)Baseline: 463.30 ops/s
136.74 ops/s
(25.82%)
unplanned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
41.07 ops/s
(+16.60%)Baseline: 35.22 ops/s
12.13 ops/s
(29.53%)
unplanned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
51.17 ops/s
(+0.12%)Baseline: 51.11 ops/s
49.10 ops/s
(95.96%)
unplanned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
35.04 ops/s
(+24.64%)Baseline: 28.11 ops/s
-2.34 ops/s
(-6.69%)
unplanned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
49.81 ops/s
(-0.47%)Baseline: 50.04 ops/s
48.06 ops/s
(96.49%)
unplanned: track.exists(playlists)📈 view plot
🚷 view threshold
3.64 ops/s
(+17.26%)Baseline: 3.10 ops/s
0.88 ops/s
(24.08%)
zpg: all playlists📈 view plot
🚷 view threshold
5.10 ops/s
(+11.34%)Baseline: 4.58 ops/s
1.73 ops/s
(33.88%)
zql: all playlists📈 view plot
🚷 view threshold
7.03 ops/s
(+4.61%)Baseline: 6.72 ops/s
5.43 ops/s
(77.28%)
zql: edit for limited query, inside the bound📈 view plot
🚷 view threshold
193,699.45 ops/s
(+0.03%)Baseline: 193,636.04 ops/s
181,856.28 ops/s
(93.89%)
zql: edit for limited query, outside the bound📈 view plot
🚷 view threshold
197,221.62 ops/s
(-1.35%)Baseline: 199,924.23 ops/s
179,767.62 ops/s
(91.15%)
zql: push into limited query, inside the bound📈 view plot
🚷 view threshold
100,140.81 ops/s
(-2.01%)Baseline: 102,197.65 ops/s
84,060.72 ops/s
(83.94%)
zql: push into limited query, outside the bound📈 view plot
🚷 view threshold
352,996.59 ops/s
(-4.37%)Baseline: 369,131.49 ops/s
329,620.29 ops/s
(93.38%)
zql: push into unlimited query📈 view plot
🚷 view threshold
307,220.22 ops/s
(-6.35%)Baseline: 328,034.89 ops/s
220,125.36 ops/s
(71.65%)
zqlite: all playlists📈 view plot
🚷 view threshold
1.63 ops/s
(+1.82%)Baseline: 1.60 ops/s
1.47 ops/s
(90.23%)
zqlite: edit for limited query, inside the bound📈 view plot
🚷 view threshold
67,230.99 ops/s
(+1.10%)Baseline: 66,502.16 ops/s
61,963.57 ops/s
(92.17%)
zqlite: edit for limited query, outside the bound📈 view plot
🚷 view threshold
61,414.61 ops/s
(-7.23%)Baseline: 66,202.67 ops/s
60,856.76 ops/s
(99.09%)
zqlite: push into limited query, inside the bound📈 view plot
🚷 view threshold
3,626.09 ops/s
(-2.23%)Baseline: 3,708.61 ops/s
3,576.63 ops/s
(98.64%)
zqlite: push into limited query, outside the bound📈 view plot
🚷 view threshold
80,023.99 ops/s
(-0.73%)Baseline: 80,615.88 ops/s
74,114.42 ops/s
(92.62%)
zqlite: push into unlimited query📈 view plot
🚷 view threshold
118,136.75 ops/s
(+1.19%)Baseline: 116,743.57 ops/s
101,248.48 ops/s
(85.70%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link

github-actions bot commented Mar 18, 2026

🐰 Bencher Report

Brancharv/collator-exploration
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
src/client/custom.bench.ts > big schema📈 view plot
🚷 view threshold
142,587.49 ops/s
(+11.39%)Baseline: 128,013.06 ops/s
117,744.88 ops/s
(82.58%)
src/client/zero.bench.ts > basics > All 1000 rows x 10 columns (numbers)📈 view plot
🚷 view threshold
2,391.04 ops/s
(+19.11%)Baseline: 2,007.37 ops/s
974.55 ops/s
(40.76%)
src/client/zero.bench.ts > pk compare > pk = N📈 view plot
🚷 view threshold
59,807.24 ops/s
(+2.73%)Baseline: 58,220.56 ops/s
54,629.48 ops/s
(91.34%)
src/client/zero.bench.ts > with filter > Lower rows 500 x 10 columns (numbers)📈 view plot
🚷 view threshold
3,721.26 ops/s
(+14.70%)Baseline: 3,244.44 ops/s
2,263.91 ops/s
(60.84%)
🐰 View full continuous benchmarking report in Bencher

@arv
Copy link
Contributor Author

arv commented Mar 18, 2026

=== Correctness: where methods disagree ===

Pair                                compareUTF8    compareJS    Intl.Collator    compareEnUS
--------------------------------------------------------------------------------
"Apple" vs "banana"                 <              <            <                <
"Zebra" vs "apple"                  <              <            >                >
"zoo" vs "élan"                     <              <            >                >
"zebra" vs "éclair"                 <              <            >                >
"strasse" vs "straße"               <              <            <                <
"zoo" vs "ænema"                    <              <            >                >
"😀" vs "😁"                        <              <            <                <
"😀" vs "🌍"                        >              >            >                >
"co-op" vs "coop"                   <              <            <                <
"re-sort" vs "resort"               <              <            <                <
"item10" vs "item9"                 <              <            <                <
"a\u0000b" vs "aa"                  <              <            >                >
clk: ~2.61 GHz
cpu: Apple M1
runtime: node 24.14.0 (arm64-darwin)

benchmark                   avg (min … max) p75 / p99    (min … top 1%)
------------------------------------------- -------------------------------
compareUTF8 (ASCII)            1.00 µs/iter 709.00 ns  █                   
                    (583.00 ns … 604.04 µs)   3.00 µs  █                   
                    (360.00  b … 229.56 kb) 385.01  b ▁█▂▁▁▁▁▁▁▁▁▁▃▁▁▁▁▁▁▁▁

compareJS (ASCII)              1.84 µs/iter   1.95 µs    █ ▆▆▃█            
                        (1.47 µs … 2.66 µs)   2.59 µs █▂ ██████▅▂ ▂▂       
                    (  0.10  b …   0.10  b)   0.10  b ██▆████████▆██▆▁▁▁▁▁▃

Intl.Collator (ASCII)          9.21 µs/iter   9.80 µs        █      █      
                       (7.84 µs … 10.85 µs)  10.74 µs ▅▅▅ ▅▅ █▅ ▅  ▅█  ▅  ▅
                    (  0.10  b …   4.25  b)   0.33  b ███▁██▁██▁█▁▁██▁▁█▁▁█

localeCompare (ASCII)          1.51 µs/iter   1.65 µs █                    
                        (1.18 µs … 2.43 µs)   2.29 µs █▇▇▂ ▇▄ ▅            
                    (  0.10  b …   1.63  b)   0.11  b █████████▆▅▂▄█▄▄▅▄▁▁▂

compareEnUS (ASCII)            1.12 µs/iter   1.24 µs  █▅█ ▇ ▂             
                      (739.54 ns … 2.01 µs)   1.89 µs ▂█████▇██  ▂         
                    (  0.10  b …   5.14  b)   0.13  b █████████▅▅█▇▅▅▇▄▁▄▂█

compareSvSE (ASCII)            1.08 µs/iter   1.22 µs ▂█                   
                      (739.34 ns … 2.82 µs)   2.36 µs ██▇▃  ▃              
                    (  0.10  b …   2.29  b)   0.11  b ████▇██▄▂▃▄▂▄▂▁▂▂▂▁▂▂

compareDeDE (ASCII)          967.96 ns/iter   1.10 µs  █                   
                      (720.84 ns … 1.82 µs)   1.76 µs ▅█                   
                    (  0.10  b …   2.25  b)   0.11  b ███▇██▄▆▄▆▅▃▃▃▃▃▁▁▂▁▂

compareEnGB (ASCII)          944.25 ns/iter   1.02 µs  ▆█                  
                      (717.68 ns … 2.05 µs)   1.59 µs  ██▅█▅▄              
                    (  0.10  b …   2.25  b)   0.11  b ▇███████▆▃▃▆▄▂▂▂▃▃▃▂▂

compareFrFR (ASCII)          976.75 ns/iter   1.08 µs  ▅█▅                 
                      (733.80 ns … 1.87 µs)   1.69 µs ▇███▂  ▄             
                    (  0.10  b …   2.25  b)   0.11  b █████████▆▆▄▂▄▄▂▁▂▁▂▄

summary
  compareEnGB (ASCII)
   1.03x faster than compareDeDE (ASCII)
   1.03x faster than compareFrFR (ASCII)
   1.06x faster than compareUTF8 (ASCII)
   1.15x faster than compareSvSE (ASCII)
   1.18x faster than compareEnUS (ASCII)
   1.6x faster than localeCompare (ASCII)
   1.94x faster than compareJS (ASCII)
   9.75x faster than Intl.Collator (ASCII)

------------------------------------------- -------------------------------
compareUTF8 (Unicode)          3.17 µs/iter   2.13 µs █                    
                      (1.79 µs … 917.29 µs)  16.04 µs █                    
                    (360.00  b … 256.01 kb) 394.58  b █▄▁▁▁▄▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

compareJS (Unicode)            3.42 µs/iter   3.75 µs      ▅     █         
                        (2.30 µs … 5.23 µs)   4.96 µs    ▆██ ▆▃  █       ▃ 
                    (  0.10  b …   0.10  b)   0.10  b █▄▄███▄██▄▁█▄▄█▁▁▄▁█▄

Intl.Collator (Unicode)       27.01 µs/iter  28.39 µs             █   █    
                      (23.74 µs … 30.56 µs)  29.74 µs ▅▅ ▅  ▅   ▅ █▅  █   ▅
                    (  0.10  b …   0.10  b)   0.10  b ██▁█▁▁█▁▁▁█▁██▁▁█▁▁▁█

localeCompare (Unicode)       22.00 µs/iter  22.74 µs        █             
                      (18.19 µs … 28.55 µs)  26.28 µs    █   █             
                    (  0.10  b …   0.10  b)   0.10  b █▁██▁▁▁██▁▁█▁▁▁▁▁▁▁██

compareEnUS (Unicode)          4.67 µs/iter   5.16 µs ██ ██    █  █        
                        (3.82 µs … 5.93 µs)   5.93 µs ██████   █  ██       
                    (  0.10  b …   5.52  b)   0.25  b ████████▁█▁▁███▁█████

compareSvSE (Unicode)          3.73 µs/iter   3.80 µs       ▃     █        
                        (3.52 µs … 4.25 µs)   3.99 µs ▂▇ ▂ ▇█▇▇▇▂ █▇▂  ▂   
                    (  0.10  b …   5.61  b)   0.22  b ██▆█▆██████▆███▁▁█▁▁▆

compareDeDE (Unicode)          3.62 µs/iter   3.54 µs ▅█                   
                        (3.45 µs … 4.82 µs)   4.55 µs ██                   
                    (  0.10  b …   2.27  b)   0.15  b ██▄▂▄▂▁▁▂▁▁▂▂▂▁▁▁▁▁▁▂

compareEnGB (Unicode)          3.71 µs/iter   3.73 µs    █                 
                        (3.53 µs … 4.26 µs)   4.19 µs  ▇▅█▇                
                    (  0.10  b …   2.27  b)   0.15  b █████▁▆█▁▁▁▆▃▁▁▃▁▁▁▃▆

compareFrFR (Unicode)          3.73 µs/iter   3.79 µs █       █            
                        (3.47 µs … 4.32 µs)   4.23 µs █    ▆▆██ ▃          
                    (  0.10  b …   2.27  b)   0.15  b ███▁▄████▄█▄▄▁▁▁▄▁▁▄▄

summary
  compareUTF8 (Unicode)
   1.08x faster than compareJS (Unicode)
   1.14x faster than compareDeDE (Unicode)
   1.17x faster than compareEnGB (Unicode)
   1.18x faster than compareSvSE (Unicode)
   1.18x faster than compareFrFR (Unicode)
   1.47x faster than compareEnUS (Unicode)
   6.94x faster than localeCompare (Unicode)
   8.52x faster than Intl.Collator (Unicode)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants