Skip to content

Add _id range, keyset pagination, ObjectId and UUID insert benchmarks - #67

Merged
macneale4 merged 5 commits into
mainfrom
macneale4/benchmark-id-range
Nov 6, 2026
Merged

macneale4 merged 5 commits into
mainfrom
macneale4/benchmark-id-range

Conversation

@macneale4

@macneale4 macneale4 commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Adds benchmarks for _id ranges, keyset pagination on _id, inserts with increasing ObjectId _ids, and UUID _id ranges and inserts. Also teaches the index-use check to recognize clustered _id scans, which dolthub/dumbodb#209 introduces.

New benchmarks

  • Find_IdRange_{Int,String,ObjectId,UUID}_{10K,50K}: find a window of n/100 consecutive _ids ($gte/$lt), moving the window each iteration. Before timing, checks the result count.
  • Find_IdPaginate_{10K,50K}: one page of {_id: {$gt: last}}, sorted on _id, limit 100, walking the whole collection. Before timing, checks the exact page of _ids in order.
  • InsertOne_ObjectId, InsertMany_ObjectId_{100,1000}: the same as InsertOne/InsertMany but with fresh driver ObjectIds. These increase as server-generated ids do, so each pair shows whether _id order changes insert cost. The existing insert benchmarks still send the same string ids.
  • InsertMany_{UUIDv4,UUIDv7,UUIDv4String}_50K_{100,1000}: insert batches into a collection seeded with 50K documents of the same _id kind, so each insert lands among existing keys. Binary (subtype 4) v4 UUIDs are random, v7 UUIDs increase, and UUIDv4String stores v4 UUIDs as 36-character strings. Before timing, each checks that the stored _id really has the intended type.

The _id benchmarks require the _id_ index on MongoDB. On DumboDB the full scan is declared as a known gap tracked by dolthub/dumbodb#207, so they pass against the current release.

Clustered _id scans

On a clustered collection, mongod and DumboDB (after #209) explain an _id range as CLUSTERED_IXSCAN with no indexName, and they read documents without index keys. The index-use check now counts that as reading _id_. For those scans it skips the "documents read <= index keys" rule but keeps the "documents read <= max(returned, n/10)" bound, so a full scan still fails.

Against #209's head (3fc21702), the _id benchmarks fail with "promote this benchmark to mustUseIndex", the intended signal. With idOrderGap set to mustUseIndex, all of them pass on both servers, including the queryExecutor read counters. After #209 merges, change idOrderGap to mustUseIndex in benchmarks/id_range_scaled_bench_test.go.

Tracker ids removed from benchmarks/

Known gaps in benchmarks/ now cite their dolthub/dumbodb issues instead of internal tracker ids: #143 (_id lookups explain as COLLSCAN), #144 ($lookup foreign index missing from explain), #142 (covered projections fetch documents) and #139 (range over half the collection). The inline duplicate of the #139 gap now reuses halfCollectionCapGap. The README and the cmd/compare comments state what their ids referred to or drop them; the README names dumbodb's TestSeekScaling_PointLookupIsLogarithmic in place of the old reference. This is folded into the first commit.

Results

Local mongod 8.0.28 and local DumboDB builds, run through cmd/compare -dumbodb-bin/-mongod-bin. Times are ms/op; before is dumbodb 5b7a9f71 (main), after is 3fc21702 (#209). The _id range rows are single 2s runs. The insert rows are the median of 3 runs of 3s each; the repetitions were within about 3% of each other, apart from one outlier per build.

_id ranges and pagination

benchmark dumbodb before dumbodb after mongodb
find_id_paginate_10k 15.83 1.21 1.12
find_id_paginate_50k 125.65 1.25 1.15
find_id_range_int_10k 3.43 1.24 1.14
find_id_range_int_50k 17.04 5.20 4.59
find_id_range_object_id_10k 19.76 1.26 1.16
find_id_range_object_id_50k 101.01 5.28 4.56
find_id_range_string_10k 20.33 1.26 1.18
find_id_range_string_50k 103.99 5.18 4.57
find_id_range_uuid_10k 20.64 1.34 1.24
find_id_range_uuid_50k 102.54 5.57 4.98

Inserts into an empty collection

benchmark dumbodb before dumbodb after mongodb
insert_one 1.75 1.70 1.42
insert_one_object_id 1.75 1.72 1.42
insert_many_100 8.81 3.36 4.44
insert_many_object_id_100 9.21 3.37 4.42
insert_many_1000 27.44 17.41 14.26
insert_many_object_id_1000 27.72 17.37 14.95

Inserts into a 50K collection

benchmark dumbodb before dumbodb after mongodb
insert_many_uuidv7_50k_100 14.32 3.99 4.48
insert_many_uuidv7_50k_1000 71.36 19.50 15.03
insert_many_uuidv4_50k_100 13.97 13.19 4.59
insert_many_uuidv4_50k_1000 71.72 66.56 17.07
insert_many_uuidv4string_50k_100 15.04 14.76 4.77
insert_many_uuidv4string_50k_1000 76.79 73.42 17.57
  • Pagination is flat from 10K to 50K after #209, as it is on MongoDB.
  • Before #209, insert cost doesn't depend on _id kind, because the hashed primary key scatters every insert. After #209, inserts with increasing keys (ObjectId, UUIDv7, and the batch-contiguous iter-<i>-<j> strings) get 1.6-3.6x faster. Random UUIDv4 keys gain only about 5% and stay 3-4x slower than MongoDB, which loses only about 12% to random keys at a batch of 1000.
  • String UUIDs cost about 10% more than binary ones on both builds.

Testing

  • go vet ./..., gofmt
  • Ran every new benchmark through cmd/compare against both builds above and MongoDB 8.0.28.

🤖 Generated with Claude Code

@macneale4
macneale4 marked this pull request as ready for review November 6, 2026 22:09
@macneale4

Copy link
Copy Markdown
Collaborator Author

Code Review Feedback: https://claude.ai/artifact/H13SbhP3hLitrb1BnscYxq

@macneale4 macneale4 changed the title Add _id range, keyset pagination, and ObjectId insert benchmarks Add _id range, keyset pagination, ObjectId and UUID insert benchmarks Nov 6, 2026
macneale4 and others added 5 commits November 6, 2026 22:46
Find_IdRange_{Int,String,ObjectId} find a sliding window of n/100
consecutive _ids, and Find_IdPaginate times one page of
{_id: {$gt: last}} sorted on _id with a limit of 100. Each checks its
results and _id_ index use before timing; DumboDB's full scan is
declared as a known gap tracked by dolthub/dumbodb#207.

Known gaps elsewhere in benchmarks/ now cite their dolthub/dumbodb
issues instead of internal tracker ids, and comments and README text
state what those ids referred to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a clustered collection, mongod and DumboDB explain an _id range as
CLUSTERED_IXSCAN with no indexName, and read documents without index
keys. Count that as reading _id_, and keep only the documents-read
bound for it in the reads check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
InsertOne_ObjectId and InsertMany_ObjectId_{100,1000} match the existing
inserts except for fresh driver ObjectIds, which increase as server
generated ids do, so the pair shows whether _id order changes insert
cost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Find_IdRange_UUID_{10K,50K} joins the _id range family with BSON binary
subtype 4 keys. InsertMany_{UUIDv4,UUIDv7,UUIDv4String}_50K_{100,1000}
insert into a collection seeded with 50K documents of the same _id kind,
contrasting random keys, increasing keys, and UUIDs stored as strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@macneale4
macneale4 force-pushed the macneale4/benchmark-id-range branch from 00f57e0 to 7fea312 Compare November 6, 2026 22:46
@macneale4
macneale4 merged commit 77a5688 into main Nov 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant