Skip to content

perf: cache column names per statement for object rows - #53

Merged
arv merged 1 commit into
mainfrom
arv/cache-column-keys
Oct 19, 2026
Merged

arv merged 1 commit into
mainfrom
arv/cache-column-keys

Conversation

@arv

@arv arv commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

get() and iterate() internalized every column name again for each row, and all() did so once per call. Statements now keep the names as v8::Global<v8::Name> handles (src/util/column-keys.cpp) and refresh them only when SQLite re-prepares the statement (SQLITE_STMTSTATUS_REPREPARE) or the column count changes. That is the only time names can change, e.g. a schema change behind SELECT *.

get(), iterate(), all() and explainQueryPlan now all build object rows through RowBuilder. Guarded by NODE_MODULE_VERSION >= 127 (needs v8::LocalVector); older Node keeps the existing path.

First of two stacked PRs; #54 builds rows from a cached v8::DictionaryTemplate on top of this.

Benchmark

Node 22.22.0, 2000-row tables with 4 and 10 columns. Runs alternate between builds; each figure is the median of 25 rounds, in µs.

case base this PR change
4 cols, all() 1056 1034 −2%
4 cols, iterate() 2266 1834 −19%
4 cols, get() ×2000 10223 9702 −5%
10 cols, all() 2087 1976 −5%
10 cols, iterate() 3826 2837 −26%
10 cols, get() ×2000 12252 11142 −9%
one-shot prepare().get() 10.08 10.48 +4%, within run-to-run noise

Tests

  • Added schema-change tests for get/all/iterate. Each runs the statement, then ALTER TABLE … RENAME COLUMN and ADD COLUMN, and asserts the rows pick up the new names.
  • Node test suite passes: 350 passing, 1 pending.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WCP5vbpvciRmgWBx2b1zKb

Copilot AI lite review requested due to automatic review settings October 19, 2026 12:06
@github-actions
github-actions Bot requested a review from tantaman October 19, 2026 12:06

arv commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

Verify Signed Commit Authors fails on 61c1840. The commit was signed with this session's SSH key (SHA256:32dP45eSMmVSt/G/CGvcxl/P+MO3Nwj9xeTh/GSA2wc), which isn't in rocicorp/.github's allowed_signers. The code is fine; the commit just needs to be re-signed with an allowed key. I can't do that from here. #54 (cb404a9) needs the same.


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Cached keys may become stale if SQLite reprepares during a later step in all() or explainQueryPlan().

1 open issue
What changed in this PR

This PR caches statement column names and reuses RowBuilder for object-row construction, reducing repeated V8 string creation.

Changes:

  • Adds per-statement column-key caching with schema invalidation.
  • Routes object-row APIs through RowBuilder on supported Node versions.
  • Adds schema-change regression tests.
File Summary
test/​23.statement.iterate.js Tests schema changes during iteration.
test/​22.statement.all.js Tests schema changes for all().
test/​21.statement.get.js Tests schema changes for get().
src/​util/​row-builder.cpp Builds rows using cached keys.
src/​util/​column-keys.cpp Implements cached column-name handles.
src/​objects/​statement.hpp Adds statement cache and row-builder state.
src/​objects/​statement.cpp Integrates cached row construction.
src/​objects/​statement-iterator.cpp Uses the statement row-conversion path.
src/​better_sqlite3.cpp Includes the new utility.

Review effort: Lite

Comment thread src/util/row-builder.cpp Resolved
get() and iterate() internalized every column name again for each row,
and all() did so once per call. Statements now keep the names as
persistent handles and refresh them only when SQLite re-prepares the
statement (SQLITE_STMTSTATUS_REPREPARE) or the column count changes,
which is the only time names can change, e.g. a schema change behind
SELECT *.
@arv
arv force-pushed the arv/cache-column-keys branch from 61c1840 to 3fa671b Compare October 19, 2026 12:15
@arv
arv added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit 144f0c4 Oct 19, 2026
26 checks passed
@arv
arv deleted the arv/cache-column-keys branch October 19, 2026 12:23
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.

2 participants