— Benchmarks
Measured,
not claimed
- Machine
- Apple M1 Pro, 8 cores, 16 GB, Node 25
- Against
- DuckDB 2.0 (@duckdb/node-api 2.0.0-r.1)
- Vectro
- d89ef84 · 2026-11-01
- Method
- Each system in its own process, best of 5 in memory and best of 3 on disk, every answer compared between the two.
In memory · 10M rows
The same SQL on 10M orders + 100K customers
The same SQL text in both, from filters and joins to window functions, percentiles, text functions and outer joins.
20/20
faster or level · best of 5, answers checked · compare/bench-sql.mjs
Vectro DuckDB · lower is better
In memory · 10M rows
Group-by on 10M rows
count(*) and sum(price * qty) per group, from 2,920 groups to 5.7 million.
4/4
faster or level · count(*) and sum(price * qty) per group, best of 5 · compare/bench-groupby.mjs
Vectro DuckDB · lower is better
In memory · 10M rows
Joins on 10M orders
The joined table built in full, then counted and summed.
4/4
faster or level · joined table built in full, then counted and summed, best of 5 · compare/bench-join.mjs
Vectro DuckDB · lower is better
In memory · 10M rows
Distinct counts on 10M rows
Exact distinct counts. The 1M accounts are evenly spaced IDs (1e9 + 7919k); 1M random IDs up to 2^40, with no common step, take 24 ms against DuckDB’s 46.
4/4
faster or level · exact; best of 5 · compare/bench-distinct.mjs
Vectro DuckDB · lower is better
On disk · bigger than memory
A Vectro dataset against a DuckDB database file
The same rows in both, made from whole-number formulas exact in JavaScript and in DuckDB, so the answers can be compared. Each query runs in a fresh process; the first run and the best of 3 are both recorded.
100M rows
| Query | Vectro | DuckDB | |
|---|---|---|---|
| scan everything | 49 ms | 61 ms | 1.2× faster |
| filter: EU, qty >= 5 | 70 ms | 72 ms | level |
| the last day (time range) | 3 ms | 1 ms | 3.0× slower |
| group by region | 114 ms | 124 ms | 1.1× faster |
| top 10 of 1M customers | 460 ms | 487 ms | 1.1× faster |
| top 10 rows by price | 10 ms | 87 ms | 8.7× faster |
| join 1M customers | 84 ms | 68 ms | 1.2× slower |
| distinct customers per region | 247 ms | 517 ms | 2.1× faster |
| file on disk | 0.5 GB | 0.5 GB | |
| peak memory (RSS) | 343 MB | 3.1 GB |
1 billion rows
| Query | Vectro | DuckDB | |
|---|---|---|---|
| scan everything | 460 ms | 648 ms | 1.4× faster |
| filter: EU, qty >= 5 | 665 ms | 723 ms | 1.1× faster |
| the last day (time range) | 3 ms | 5 ms | 1.7× faster |
| group by region | 1.13 s | 1.24 s | 1.1× faster |
| top 10 of 1M customers | 4.46 s | 4.62 s | level |
| top 10 rows by price | 11 ms | 827 ms | 75.2× faster |
| join 1M customers | 745 ms | 587 ms | 1.3× slower |
| distinct customers per region | 2.45 s | 6.50 s | 2.7× faster |
| file on disk | 5.1 GB | 5.4 GB | |
| peak memory (RSS) | 0.37 GB | 6.6 GB |
Where DuckDB is still faster
A join over a file with a GROUP BY on the joined table's columns: 1.2× slower at 100M rows and 1.3× at a billion. And single-chunk lookups like "the last day" take a millisecond or two more than DuckDB's at 100M rows. Both are listed as they are.
Run them yourself
cd compare && npm install node bench-sql.mjs node bench-groupby.mjs node bench-join.mjs node bench-distinct.mjs ROWS=1000000000 node bench-dataset.mjs
Or race Vectro, DuckDB-WASM and Arquero in this browser on the live page.