Benchmarks

Measured, not promised

Every number on this page is measured on the same machine, through the same pymongo client, against the same on-disk WiredTiger storage — with real mongod as the reference. Two dimensions: per-operation latency (one client, six workloads) and throughput under concurrent writers (1–8 parallel writer processes). Both harnesses ship in the repo; both tables regenerate with one command.

Per-operation latency

Bar length is how many times slower than mongod each server is — median of five runs per workload, 10,000-document dataset, end-to-end through the wire protocol and driver.

Rust DB Python DB mongod = 1x reference
5x10x15x20x25xmongod = 1xinsert (10k docs)1.2x4.7xfind indexed range1.5x7.3xfind full scan2.3x8.3xfind filtered scan1.7x12.8xupdate_many (half)1.1x13.3xaggregate $group0.9x17.4xaggregate multi-stage1.7x24.3xdelete_many (half)0.8x10.5xchange-stream drain0.8x1.4x
Data table (with raw milliseconds)
WorkloadmongodRust DBx mongodPython DBx mongod
insert (10k docs)55.0 ms65.8 ms1.2x256.7 ms4.7x
find indexed range4.3 ms6.3 ms1.5x31.5 ms7.3x
find full scan7.3 ms16.7 ms2.3x60.4 ms8.3x
find filtered scan5.5 ms9.2 ms1.7x70.2 ms12.8x
update_many (half)33.4 ms36.8 ms1.1x445.9 ms13.3x
aggregate $group5.5 ms5.1 ms0.9x95.3 ms17.4x
aggregate multi-stage5.8 ms9.9 ms1.7x142.0 ms24.3x
delete_many (half)20.9 ms17.6 ms0.8x218.2 ms10.5x
change-stream drain*45.8 ms36.9 ms0.8x64.3 ms1.4x

The short version: the Rust DB runs at 0.8x–2.3x of mongod per operation — delete, single-stage $group, and the change-stream drain now beat mongod outright — and it is roughly 1.7x–19x faster than the Python DB workload-for-workload. All three sit on the identical WiredTiger C library; the gaps are the layers above it. (* The change-stream row's mongod reference is a single-node replica set — mongod's change streams require one.) Methodology & how to reproduce →

Throughput under concurrent writers

Does throughput grow with writers? Each line is a server's aggregate throughput relative to its own single-writer rate — N writer processes each streaming insert_many batches for 30 seconds against their own collections.

mongodRust DBPython DBRust DB — async stack
1x2x3x4x1248concurrent writersmongod 4.6xRust 2.7xPython 0.6xasync 2.4x
Data table (absolute docs/second)
WritersmongodRust DBRust DB — async stackPython DB
1105,70035,40050,40012,100
2203,30053,70066,0008,900
4366,10080,200100,30010,400
8481,00096,400119,2007,600

Three different shapes, honestly told. mongod scales — 4.6x its own single-writer aggregate at eight writers; that's its C++ scheduler above WiredTiger doing its job. The Rust DB scales monotonically — 1.5x at two writers, 2.3x at four, 2.7x at eight (~96k docs/s aggregate), with no cliff: the per-collection write-lock split, RecordId keying (write amplification cut from four WiredTiger writes per document to three), a key-only oplog prune, and append-tuned oplog btrees turned the old peak-then-collapse shape into real scaling at every writer count, fully durable. The remaining flattening is WiredTiger itself — cache eviction and checkpoint pressure in one embedded connection — not a SecantusDB lock. The Rust DB's async stack sits highest (dashed) — opting into the async + non-logged oplog (oplog_async + oplog_nonlogged, options on the embedded handle and daemon flags, or the SECANTUS_* env vars) moves the oplog write off the writers' critical path and out of the write-ahead log: ~119k docs/s at eight writers, ~1.2x the fully-durable default, trading crash durability of the oplog tail (data stays fully durable; change streams stay exactly-once). The Python DB degrades under contention to ~0.6x — the GIL plus the measured WiredTiger-binding ceiling — but degrades gracefully: write conflicts retry server-side exactly like mongod's writeConflictRetry, and a client never sees an error. The full concurrency story →

What to make of it

SecantusDB's trade is deliberate: conformance and WiredTiger durability over raw speed. For its home turf — embedded test and dev databases, single-node prototypes, CI — per-operation latency in the milliseconds and single-writer throughput in the thousands of documents per second rarely matter. When they do, the Rust DB is the answer within the family, and a real mongod is the answer beyond it — and because the wire protocol is identical, moving between all three is a connection-string change.

Caveats that apply to every number here: one machine (Apple Silicon), no network, no concurrent readers mixed with writers, dataset that fits in cache. The harnesses (bench.compare_servers, bench.concurrency) ship in the repository — run them on your own hardware and workload before drawing conclusions that matter.