Benchmarks, honestly

Median of N runs, both engines warm, prepared statements on both sides, fsync to a real disk. Where SQLite wins, we show it — the chart is only useful if you can trust it.

AMD Ryzen 7 3700X · 32 GiB · ext4 on SATA SSD · rustc 1.95.0 · SQLite 3.50.2 · single-threaded

The scoreboard

Every CRUD operation, as a speed ratio. Right of the line, Arkeion is faster; left of it, SQLite is — and yes, the full scan is still theirs.

0.5×evenSELECT by PK3.13×DELETE durable2.5×INSERT durable2.42×UPDATE durable2.06×SELECT by index1.98×Bulk-load API1.17×Batch insert (SQL)1.02×Full scan0.48×
Each dot wears the winner's color. Hover a dot for the raw numbers; the axis is logarithmic so 2× and ½× sit at equal distances from parity.

Durable writes — the core use case

Every committed transaction pays the fsync. Arkeion's append-only commit needs one fdatasync; SQLite at synchronous=FULL pays two. On real disk that flips the table — and it's what an audited engine does constantly.

INSERT, durable 2.42×× 656 vs 271 ops/s
UPDATE, durable 2.06×× 572 vs 278 ops/s
DELETE, durable 2.50×× 657 vs 263 ops/s

Same guarantees — the fair fight

The scoreboard above races plain SQLite. But Arkeion always carries versioning, a per-commit hash chain, AS OF and verify(). Hand SQLite the same job — a full history table plus a per-write hash chain, in one transaction — and the gap widens: this is the cost of an audit trail SQLite must bolt on and Arkeion simply is.

Durable insert, same guarantees, durable 2.51×× 656 vs 261 ops/s
Batch insert, same guarantees, durable 2.19×× 1.99M vs 906k ops/s

The SQLite emulation reproduces neither the per-commit content hash nor a queryable snapshot, so these ratios are a lower bound on the real cost of matching Arkeion — which still ships AS OF, verify() and branching on top.

Full-text vs FTS5 — a split decision

The index ended up smaller than FTS5's; build and query speed are still FTS5's turf. The trade buys something FTS5 can't offer: versioned, provable, time-travelling search.

Index size, same corpus
Arkeion
Arkeion: 26.2 MB
26.2 MB
SQLite
SQLite: 27.2 MB
27.2 MB

Prefix-compressed posting lists — and unlike FTS5, every posting is versioned, hash-chained and MATCH … AS OF searchable.

Index build (5.5M postings) FTS5 18× faster
Arkeion
Arkeion: 11 s
11 s
SQLite
SQLite: 0.6 s
0.6 s
Query, common term FTS5 2.3× faster
Arkeion
Arkeion: 2.5 ms
2.5 ms
SQLite
SQLite: 1.1 ms
1.1 ms

Vector search vs the field

SIFT 1M, 128 dimensions, L2, real top-100 ground truth, single query at recall ≈ 0.99. Under concurrent load it sustains ~700 qps on 8 cores; at recall ≈ 0.88 a single query does ~590 qps.

Throughput @ recall ≈ 0.99
Qdrant (HNSW)
Qdrant (HNSW): 508 qps
508 qps
Arkeion (IVF-PQ)
Arkeion (IVF-PQ): 356 qps
356 qps
pgvector HNSW
pgvector HNSW: 188 qps
188 qps
pgvector IVFFlat
pgvector IVFFlat: 63 qps
63 qps
Index size
pgvector HNSW
pgvector HNSW: 820 MB
820 MB
pgvector IVFFlat
pgvector IVFFlat: 551 MB
551 MB
Arkeion (IVF-PQ)
Arkeion (IVF-PQ): ~39 MB
~39 MB

14–21× smaller than the HNSW indexes — it fits in a fraction of the RAM. Qdrant does not report a comparable file size.

Index build
pgvector HNSW
pgvector HNSW: 324 s
324 s
Arkeion (IVF-PQ)
Arkeion (IVF-PQ): 64 s
64 s
Qdrant (HNSW)
Qdrant (HNSW): 49 s
49 s
pgvector IVFFlat
pgvector IVFFlat: 23 s
23 s

Parallel and streaming (186 s → 64 s): the dataset is never materialized, so it scales to tens of millions of rows on a modest box.

Read it fairly: pgvector and Qdrant answer over localhost TCP, so a 0.05–0.2 ms round trip inflates their latencies; and IVF scans O(N) candidates at fixed recall while HNSW is O(log N), so dedicated graph engines pull ahead at tens of millions of vectors. HNSW itself is excluded by design here — its random-access graph is incompatible with copy-on-write versioning and time travel. Arkeion is the one file where vectors live next to SQL, full-text, branches and AS OF.

The price of durability — v0.13 vs FAISS

The hardest comparison we can make: FAISS is the reference ANN library — pure RAM, no durability, no transactions, no versioning, no SQL. Same box (a 4-core VM, so the bars above and below are not cross-comparable), same SIFT-1M, identical config on both sides: IVF 1000 lists, PQ16, exact rerank ×32. Recall@10 ≈ 0.99 on both, query at a time, one thread.

Throughput @ recall ≈ 0.99, single thread
FAISS (in-RAM library)
FAISS (in-RAM library): 756 qps
756 qps
Arkeion v0.13 (in-file)
Arkeion v0.13 (in-file): 404 qps
404 qps
Arkeion v0.12
Arkeion v0.12: 110 qps
110 qps

Within 2× of the in-RAM reference — from a versioned, durable file on disk. Before v0.13 the gap was 7–10×. FAISS batch mode on 8 threads reaches ~5,000 qps to Arkeion's 1,381 concurrent.

Smaller on disk

The same compressible dataset, written by both engines. Page packing plus pure-Rust LZSS — Arkeion started this work at 4.0 MB.

Run them yourself

# CRUD vs SQLite (point at a real disk, not tmpfs)
ARKEION_BENCH_DIR=/path/on/real/disk cargo bench --features bench-sqlite

# on-disk footprint
cargo run --release --example dbsize --features bench-sqlite

A lesson we learned the hard way: on tmpfs the fsyncs are free and SQLite wins the durable writes. On a real disk it flips. Always bench on the disk you'll run on.

Convinced? It's one command away

Read the bench code