Every figure on this page comes from a measured run, and each one states the conditions it was measured under. Raw results are in BENCHMARK_RESULTS.md in the repo. No projected numbers, no competitor numbers we did not measure. No other database has been run on the same hardware yet: the same-hardware harness (bench/compare) exists, but its Aerospike and ScyllaDB paths are only compile-checked.
YCSB 0.17.0, June 9 2026 · pure-Go build (historical: it predates the native index, the binary WAL and --net) · AWS EC2 high-memory, 495 GB RAM · 4× NVMe, raw block VLog · 400 GB LIRS cache · 200 client threads · 100M keys × ~100 B values. The YCSB 0.17.0 binding used is not in the repo, so this run cannot be re-run from it; bench/compare (go-ycsb, below) is the reproducible YCSB path.
Same run as above. Reads are cache hits (the whole dataset fit in the 400 GB cache), so this is not a disk-read latency. Writes wait for fdatasync.
| Operation | Avg | P95 | P99 | Conditions |
|---|---|---|---|---|
| Read (workload C) | 461 µs | 2,069 µs | 2,771 µs | 10M ops, 100% cache hits, 427,697 ops/s |
| Write (100M-key load) | 11.06 ms | 30.8 ms | 47.3 ms | fdatasync-durable, 5 ms windows, 18,064 ops/s |
pread of a 4 KB-aligned VLog block, checked with magic + CRC32C. That is not io_uring and not zero-copy. The in-process cache hit itself costs ~92 ns; the rest of the read latency above is spent outside the cache lookup (network round trip, protocol, 200 concurrent clients).Taken while building adaptive group commit, vector / text / hybrid search, PQ and the disk graph. All on one macOS laptop (Apple silicon) unless stated, so the absolute numbers do not predict a Linux NVMe server. None of them is a comparison with another database. Each table names the command that reproduces it.
Adaptive group commit is the default since v1.12 (--group-commit=adaptive). The flush window becomes an upper bound: a lone writer is synced at once, and concurrent writers are synced after an idle gap of about one fdatasync. Conditions: the device’s fdatasync cost is emulated (a sleep before the real sync), because macOS fsync returns at the drive cache. 15 ms window, 128 B values, each writer doing sequential durable Puts for 1.5 s.
| Writers | Mode | P50 | P99 | Writes/s | Writes per fdatasync |
|---|---|---|---|---|---|
| Emulated sync = 300 µs (NVMe-like) | |||||
| 1 | fixed | 16.01 ms | 17.76 ms | 63 | 1.0 |
| 1 | adaptive | 0.45 ms | 0.52 ms | 2,186 | 1.0 |
| 8 | fixed | 16.02 ms | 16.39 ms | 501 | 8.0 |
| 8 | adaptive | 0.96 ms | 1.22 ms | 8,283 | 8.0 |
| 64 | fixed | 15.94 ms | 16.81 ms | 4,053 | 64.0 |
| 64 | adaptive | 1.67 ms | 2.64 ms | 37,504 | 63.9 |
| 256 | fixed | 16.40 ms | 33.15 ms | 15,291 | 249.3 |
| 256 | adaptive | 3.18 ms | 11.54 ms | 73,999 | 255.2 |
| Emulated sync = 2 ms (slow / network disk) | |||||
| 1 | fixed | 18.10 ms | 23.68 ms | 55 | — |
| 1 | adaptive | 2.41 ms | 2.52 ms | 417 | — |
| 64 | fixed | 18.18 ms | 19.12 ms | 3,541 | — |
| 64 | adaptive | 5.40 ms | 7.07 ms | 11,691 | — |
| 256 | fixed | 18.32 ms | 35.17 ms | 13,705 | — |
| 256 | adaptive | 6.96 ms | 18.56 ms | 32,277 | — |
Batches are as large as in fixed mode (about 64 writes per sync at 64 writers), so adaptive mode does not cost more IOPS under load. The 2 ms run did not record writes per sync. --group-commit=fixed restores the old behaviour, where every batch waits the whole window.
VELTRIX_GC_TABLE=1 go test ./storage -run TestGroupCommit_LatencyTable -v
Conditions: go-ycsb core workloads (bench/compare/cmd/ycsb) against a local server on the same laptop. 20,000 records × 10 fields × 100 B, 20,000 operations, 16 threads, zipfian, whole-record writes. macOS fsync does not reach the platter, so the write latencies here are a lower bound. This is not the June YCSB 0.17.0 run above, and the two are not comparable.
| Workload | Op | Ops/s | Avg | P99 | P99.9 |
|---|---|---|---|---|---|
| load | INSERT | 37,495 | 419 µs | 1.29 ms | 2.04 ms |
| A (50/50 read/update) | total | 34,640 | 453 µs | 1.30 ms | 2.98 ms |
| READ | 17,230 | 262 µs | 0.77 ms | 1.55 ms | |
| UPDATE | 17,434 | 642 µs | 1.63 ms | 3.14 ms | |
| B (95/5) | total | 52,255 | 303 µs | 0.65 ms | 0.74 ms |
| C (read only) | READ | 55,287 | 287 µs | 0.39 ms | 0.53 ms |
| D (read latest) | total | 55,163 | 288 µs | 0.39 ms | 0.59 ms |
| E (short scans) | SCAN | 23,651 | 638 µs | 1.43 ms | 1.97 ms |
| F (read-modify-write) | total | 40,067 | 392 µs | 0.81 ms | 0.98 ms |
| READ_MODIFY_WRITE | 13,397 | 915 µs | 1.22 ms | 1.49 ms |
cd bench/compare && START=0 DBS=veltrixdb RECORDS=20000 OPS=20000 THREADS=16 WORKLOADS="a b c d e f" ./compare.sh
compare.sh can also drive Aerospike and ScyllaDB one at a time on the same machine, but those drivers have only been compiled, not run, and no shared run has been published. Workload E uses VeltrixDB’s RANGE over the ordered key index.
Conditions: the first 100,000 words of GloVe-100 (angular), 100 dimensions, 500 queries, exact cosine ground truth. In-process, one query at a time, macOS (Apple silicon, GOMAXPROCS = 18). Each cell is recall@10 and p50 latency.
| Layout | ef = 64 | ef = 128 | ef = 256 | ef = 512 |
|---|---|---|---|---|
| float32 | 0.842 · 0.25 ms | 0.906 · 0.42 ms | 0.953 · 0.77 ms | 0.983 · 1.43 ms |
| int8 | 0.839 · 0.61 ms | 0.905 · 0.55 ms | 0.952 · 0.72 ms | 0.983 · 1.18 ms |
| pq (m = 25) | 0.797 · 0.56 ms | 0.870 · 0.72 ms | 0.927 · 1.17 ms | 0.969 · 1.56 ms |
| pq + disk graph | 0.788 · 0.55 ms | 0.875 · 0.66 ms | 0.931 · 1.06 ms | 0.966 · 1.60 ms |
At this size the quantized layouts are slower per query than float32, because they re-rank candidates against the full vectors read back from the VLog. They exist to save RAM, and at 100 dimensions the graph edges, not the vectors, take most of it. float32 at ef = 128: p99 0.63 ms, 2,351 QPS on one thread.
scripts/ann-dataset.py glove-100-angular /tmp/ann --train 100000 --test 500
VELTRIX_ANN_DIR=/tmp/ann go test ./storage -run TestRealEmbeddings -v -timeout 30m
Over the network. GloVe-100, first 20,000 words, 300 queries, int8, 8 concurrent clients. Server and client on the same macOS machine (bench/compare/cmd/vecbench).
| ef | recall@10 | QPS | p50 | p99 |
|---|---|---|---|---|
| 64 | 0.894 | 24,637 | 0.28 ms | 0.68 ms |
| 256 | 0.985 | 15,629 | 0.48 ms | 0.91 ms |
cd bench/compare && go run ./cmd/vecbench -data /tmp/ann -train 20000 -quant int8 -threads 8
RAM per vector at 768 dimensions. Go heap per vector, 10,000 synthetic clustered vectors, macOS. The full float32 vectors always stay on NVMe; this is what RAM holds.
| Layout | Heap / vector | Mapped file / vector | vs float32 |
|---|---|---|---|
| float32 | 3,383 B | — | 1× |
| int8 | 1,078 B | — | 3.1× less |
| pq, m = 96 | 493 B | — | 6.9× less |
| pq, m = 96 + disk graph | 378 B | 216 B | 8.9× less heap |
VELTRIX_VECTOR_MEMORY=1 go test ./storage -run TestVectorMemoryTable -v
Tested up to 100K real vectors and 10K at 768 dimensions; nothing at 10M+ yet. No other vector database has been run on the same hardware. Tuning: performance tuning, vector search.
| Test | Result | Reproduce |
|---|---|---|
| Search soak, 60 s, 4 writers + 4 searchers, 5K-id space (macOS) | 201,573 writes and 292,079 searches; 0 results outside the oracle of acknowledged writes; 288,025 self-queries with 0 misses; RSS flat at ~1.0 GB; exact oracle match before and after restart | VELTRIX_SOAK_DURATION=60s go test ./tests/integration -run TestSearchSoak -v (nightly: 20 min on Linux) |
| Crash chaos, SIGKILL mid-write (macOS) | 3 cycles with 8,524 / 8,380 / 11,851 acknowledged writes, all visible after restart and index rebuild; no deleted id returned | VELTRIX_CHAOS_CYCLES=3 go test ./tests/integration -run TestSearchCrashRecovery -v (nightly: 10 cycles) |
| Raft failover read barrier | without it, a new leader missed the acknowledged write in 20 / 20 test rounds; with it, 0 / 20 | go test ./consensus -run TestWaitLeaderApplied_FailoverVisibility -v |
Writes in flight at the kill are not checked. After each cycle the test rewrites every such id to a fresh, fully acknowledged version, so later cycles check it again.
Every node serves Prometheus metrics on /metrics (--metrics-addr, default :2112, alongside /healthz and /readyz). Below is an illustrative layout of what it exposes: metric names only, no values. It is not a snapshot of a real cluster.
veltrixdb_storage_write_latency_seconds
veltrixdb_storage_wal_flushes_total
veltrixdb_storage_wal_batch_entries_total
veltrixdb_vlog_garbage_ratio{disk}
veltrixdb_vlog_disk_slow{disk}
veltrixdb_storage_native_index_bytes
veltrixdb_scrub_corruption_total
veltrixdb_scrub_records_total
veltrixdb_cluster_nodes_total
veltrixdb_replication_lag_nanoseconds
veltrixdb_server_active_connections
histogram_quantile()
native_index_bytes is 0 on the Go map index (native index, since v1.6)
All of this has shipped, in v1.6, v1.7, v1.11 and v1.12 (v1.13 was a documentation release; v1.16 is the latest). The experimental and investigating items ship as opt-in switches. Each item lists what we measured and under which conditions, including the result that did not go our way. No dates are promised.
vm.max_map_count ≥ 262144. VELTRIXDB_INDEX=map opts out. Since v1.6.| or a newline truncated text-WAL replay, so acknowledged writes could be lost on a crash restart. The reader accepts binary and legacy text records mixed; --wal-format=text is the rollback. Since v1.6.--net=cpp)scripts/net-bench.sh runs each engine variant separately to find out. Meanwhile the io_uring write bridge is opt-in (VELTRIXDB_URING_BRIDGE, default off).fdatasync after an idle gap of about one sync. With an emulated 300 µs sync and the 15 ms default window (macOS), one writer’s P50 went 16.0 → 0.45 ms and 64 writers 4.0K → 37.5K writes/s at the same writes per sync. --group-commit=fixed restores the old behaviour. Full table. Since v1.12.QUANT pq) and GRAPH disk, which moves layer-0 HNSW edges to a memory-mapped file. On GloVe-100 (100K words, in-process, macOS) float32 reaches recall@10 0.953 at ef = 256 with p50 0.77 ms. Searches are refused while the index rebuilds after a restart. All numbers.git clone https://github.com/VeltrixDB/veltrixdb && cd veltrixdb && ./scripts/bench.sh
scripts/net-bench.sh, the October 2026 tables from the commands printed under each (see BENCHMARKING.md)