Give every Collection an implicit _id_ index (a normal Index with keys
[_id: 1]) so _id equality, $in, ranges and sorts stop depending on the
docs-map hash or a full scan. Kept out of the secondary indexes list, so
listIndexes/dropIndexes/createIndex and the log format are unchanged (no
index_create record, no double listing) and e2e3.js passes unmodified.
Maintained in upsert through the same reserve-then-insert protocol as
the secondaries, removed in evict_doc, and rebuilt after replay by
build_all_indexes alongside them (never maintained mid-replay, so a
failed add can't leave the index under-approximating). index.plan now
takes it as a separate argument. Its keys are canonical
(bson.encode_key gives int32 1, int64 1 and double 1.0 identical bytes),
so the serialization-guarded docs-map fast path (plan_id,
value_fast_path_safe and friends) is deleted.
Measured (tests/e2e/results/phase3.txt): sort({_id:-1}).limit(20) 6.2 ->
2.4 ms (2.3x slower than MongoDB -> parity); integer/string _id point
lookups, $in and ranges verified against the tree. Unit suite in all
three optimize modes, the crash pair, e2e3/e2e4/e2e6.
39 lines
2.8 KiB
Plaintext
39 lines
2.8 KiB
Plaintext
# Phase 3 gate — mongo-lite vs MongoDB 8.3.7, 1g dataset / ~16k docs
|
||
# Ratio < 1.0 = mongo-lite faster. Reproduce: bash tests/e2e/compare-run.sh 1g 16k
|
||
# This run includes roadmap items 1 (B+tree) and 2 (ordered _id index).
|
||
# Compare: tests/e2e/results/phase1.txt (pre-tree baseline).
|
||
|
||
benchmark mongo-lite mongodb ratio
|
||
insertOne (sequential) ×200 0.19 ms 4.4 ms 0.0x
|
||
bulk insert throughput 816.5 MB/s 716.8 MB/s 1.1x
|
||
docs loaded 65,536 65,536 1.0x
|
||
createIndex({k: 1}) 50.7 ms 76.8 ms 0.7x
|
||
countDocuments({}) 1.5 ms 11.1 ms 0.1x
|
||
findOne({_id: <ObjectId>}) 0.57 ms 0.64 ms 0.9x
|
||
findOne({k: 500}) (indexed) 0.58 ms 1.5 ms 0.4x
|
||
find({p: {$gte,$lt}}).count() (scan) 22.1 ms 12.9 ms 1.7x
|
||
find({}).sort({_id:-1}).limit(20) 2.4 ms 2.2 ms 1.1x
|
||
find({}, {proj}).limit(1000) 3.7 ms 4.3 ms 0.9x
|
||
aggregate $group by k 9.1 ms 12.5 ms 0.7x
|
||
updateOne({_id}) ×50 0.16 ms 0.19 ms 0.8x
|
||
updateMany({k: 7}, {$inc}) 1.6 ms 6.4 ms 0.3x
|
||
deleteOne({_id}) + insertOne 0.62 ms 4.8 ms 0.1x
|
||
node client RSS 159 MB 156 MB 1.0x
|
||
server RSS 1973 MB 1334 MB
|
||
kill -9 reopen 0.8s 1.3s
|
||
db on disk 1025MB 91MB
|
||
|
||
# Item 2 (ordered _id index) deltas vs phase2:
|
||
# sort({_id:-1}).limit(20) 6.2 -> 2.4 ms (2.3x slower than mongod -> parity):
|
||
# the sort planner now scans the _id tree in order and stops
|
||
# at the page limit instead of materializing every candidate.
|
||
# integer/string _id findOne, updateOne, deleteOne no longer fall back to a
|
||
# full collection scan (verified separately: point lookups,
|
||
# $in, ranges, int64/int32 compare-equal equality all hit the
|
||
# tree; the docs-map serialization-guard fast path is gone).
|
||
#
|
||
# Remaining gaps and where they are addressed:
|
||
# db on disk 11x -> Phase 3 (block-compressed log)
|
||
# range-scan 1.7x -> Phase 4 (contiguous byte storage, not the matcher)
|
||
# server RSS 1.5x -> Phase 4 (per-document arena -> byte storage)
|