perf: sqlite prepare cached#7414
Merged
francesco-stacks merged 5 commits intoJul 17, 2026
Merged
Conversation
…e per-connection statement-cache capacity
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves SQLite query performance by switching hot-path queries to use rusqlite’s prepared-statement cache (prepare_cached) and increasing per-connection statement-cache capacity to reduce repeated SQL parsing.
Changes:
- Use
prepare_cachedin shared SQLite query helpers and several frequently-called read paths (Clarity VM headers queries, MARF squashed-block lookups, SortDB tip lookups). - Increase prepared-statement cache capacity on long-lived connections (
stackslib: 200; Clarity side-store: 32). - Add a changelog fragment documenting the performance improvement.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| stackslib/src/util_lib/db.rs | Switch generic query_* helpers and a MARF lookup to prepare_cached; bump per-connection statement-cache capacity to 200 in sqlite_open(). |
| stackslib/src/clarity_vm/database/mod.rs | Cache dynamically-built header-table SELECT statements via prepare_cached for repeated access patterns. |
| stackslib/src/chainstate/stacks/index/trie_sql.rs | Use prepare_cached for MARF squashed-block and block-id/hash lookup queries. |
| stackslib/src/chainstate/burn/db/sortdb.rs | Use prepare_cached for canonical tip lookup queries in SortDB. |
| clarity/src/vm/database/sqlite.rs | Use prepare_cached for side-store reads/writes; bump statement-cache capacity to 32. |
| changelog.d/sqlite-prepare-cached.changed | Document statement caching + cache-capacity increase. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
francesco-stacks
marked this pull request as ready for review
July 14, 2026 09:26
francesco-stacks
requested review from
benjamin-stacks,
cylewitruk-stacks and
federico-stacks
July 14, 2026 09:26
Coverage Report for CI Build 29476362671Coverage increased (+0.8%) to 86.538%Details
Uncovered Changes
Coverage Regressions12003 previously-covered lines in 165 files lost coverage.
Coverage Stats
💛 - Coveralls |
francesco-stacks
enabled auto-merge
July 14, 2026 12:14
benjamin-stacks
approved these changes
Jul 16, 2026
federico-stacks
approved these changes
Jul 17, 2026
Merged
via the queue into
stacks-network:develop
with commit Jul 17, 2026
a14e5e0
451 of 454 checks passed
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.
Description
Profiling a mainnet follower during catch-up (on top of #7300) showed the SQLite SQL parser (
resolveExprStep,sqlite3RunParser,yy_reduce) as the largest remaining CPU sink: ~5.3% of chains-coordinator self-time. We re-compile the same SQL strings millions of times (the Clarity side store on every data read, the MARF on every trie-cache miss, and thequery_*helpers inutil_lib/db.rsfor every caller).rusqlite ships a per-connection prepared-statement cache,
prepare_cached, which compiles once and reuses the bytecode. We just don't use it on these paths, and its default capacity (16) would LRU-thrash under the node's breadth of statements.This PR routes the hot read paths through the cache and raises the per-connection cache capacity to 200 in
sqlite_open.Measured impact - A/B on a mainnet follower (identical chainstate copies, same start height, 10-minute windows):
I also run a first iteration (that wasn't caching everything this one is caching) with stacks-bench in cylewitruk#5 (comment) that measured it ~4% faster during the benchmark.
Applicable issues
Additional info (benefits, drawbacks, caveats)
Checklist
docs/property-testing.md)changelog.d/README.md)rpc/openapi.yamlfor RPC endpoints,event-dispatcher.mdfor new events)clarity-benchmarkingrepo