Reduce INSERT allocations via autoincrement key cache and single-row rowValues alias - #327
Merged
Merged
Conversation
…rowValues alias Add lastAutoincrementKey atomic.Int64 to Table (initialised to -1) so that insertAutoincrementedPrimaryKey can skip the per-insert SeekLastKey B-tree traversal. The cold path (cache == -1) calls SeekLastKey once to seed the cache; the hot path uses cache+1 directly and stores the new key after a successful insert, eliminating one O(log N) traversal and one int64→any boxing per autoincrement INSERT. Explicit-key inserts into autoincrement tables now update the cache to max(cache, newKey) via a CAS high-water loop so that a mix of explicit and auto-generated inserts (e.g. INSERT INTO t (id,...) VALUES (100,...) followed by autoincrement inserts) still produces monotonically increasing, collision- free keys. Table.Insert no longer allocates a rowValues buffer for single-row inserts arriving in column order (the post-prepareInsert fast path). rowValues is aliased directly to the values slice, eliminating one make([]OptionalValue, N) per prepared-statement exec. Multi-row statements still pre-allocate the shared reuse buffer. Net effect on batch/prepared-batch INSERT (100 rows/tx): allocs: 2,143 → 1,954 (-8.8%), memory: 123 KiB → 115 KiB (-6.5%) Multi-values INSERT: allocs 1,457 → 1,363 (-6.5%) (single-row optimisation does not apply; only the SeekLastKey saving contributes). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code Coverage✅ Total: 70.4% (threshold: 70%)
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
lastAutoincrementKey atomic.Int64onTable): eliminates the per-insertSeekLastKeyB-tree traversal and itsint64→anyboxing. Cold start (cache = −1) callsSeekLastKeyonce; all subsequent autoincrement inserts usecache + 1directly. Explicit PK inserts on autoincrement tables update the cache via a CAS high-water loop so a mix of explicit and auto-generated keys stays collision-free.rowValuesalias (Table.Insert): when inserting one row whose values are already in column order (the post-prepareInsertfast path),rowValuesis aliased directly tovaluesinstead of copying into a freshly allocated[]OptionalValue. Multi-row statements still pre-allocate the shared reuse buffer as before.Benchmark results
The savings on
multi-valuesare smaller because that path has multiple rows per statement (len(stmt.Inserts) > 1), so the single-row alias optimisation does not apply; only the SeekLastKey elimination contributes.Test plan
LOG_LEVEL=error go test ./... -count=1)BenchmarkInsert_PreparedBatch,BenchmarkInsert_Batch,BenchmarkInsert_MultiValuesrun cleanlyTestSelectsuite (which mixes explicit and autoincrement PK inserts) passes — this was the key correctness check for the high-water-mark CAS ininsertPrimaryKey🤖 Generated with Claude Code