Up to 3.4× faster statement preparation via in-place authorizer region accumulation#1873
Open
guidedways wants to merge 1 commit into
Open
Conversation
Accumulate individual SQLite read events in a single database-region slot. Cover equivalence with general region unions and add a reproducible statement-preparation benchmark.
guidedways
marked this pull request as ready for review
July 20, 2026 05:47
Owner
|
Thank you @guidedways! I'll review this pull request shortly! |
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.
SQLite invokes the statement authorizer once for every column read while compiling a statement.
StatementAuthorizerhandled eachSQLITE_READevent by building a one-columnDatabaseRegionand merging it withDatabaseRegion.formUnion, which rebuilds the table dictionary and column sets on every call. Compiling a statement that reads C columns therefore performs O(C²) region work, with temporary allocations on every callback. In a production app querying an 80-column table, this accounted for 1.73 seconds of main-thread time in a three-minute profile, from only a couple hundred statement preparations.The authorizer now records each read through an internal
DatabaseRegionoperation that mutates one dictionary slot in place, making each callback O(1) amortized. Whole-table reads still promote a table region to all columns, a full-database region still absorbs every read, and the generalunion/formUnionoperations are untouched. No public API or observable behavior changes.Performance
Median of five release-build samples, each compiling 1,000 fresh statements after 100 warm-ups (
Database.makeStatement(sql:), in-memory database):SELECT *from a 120-column tableSELECT idnarrow controlSmall statements improve as well, since the per-callback region construction and merge are gone regardless of statement width.
MacBook Pro (Apple M3 Max), macOS 26.5.1, Swift 6.3.2, system SQLite 3.51.0, default SPM configuration. Reproduce from the repository root:
swift test -c release --filter StatementPreparationPerformanceTestsThe benchmark skips itself in debug builds, so plain
swift testrun time is unaffected.As a broader check, five alternated release runs of the identical pre-existing test suite completed with a 1.6% lower median on this branch (76.2 s → 75.0 s). The effect is small, as expected: the suite's statements are mostly narrow and statement preparation is a minor share of its total time, so it exercises the affected path far less than the benchmark above.
Correctness
The new operation produces regions equal (
==) to theformUnionfold it replaces.DatabaseRegionTestscovers:testRegionFormUnionTableColumntestRegionFormUnionTableColumnWholeTabletestRegionFormUnionTableColumnRepeatedColumntestRegionFormUnionTableColumnMultipleTablestestRegionFormUnionTableColumnCaseInsensitiveTabletestRegionFormUnionTableColumnAndRowIdstestRegionFormUnionTableColumnFullDatabasetestRegionFormUnionTableColumnSequenceEquivalencetestSelectStatement,testSelectStatement_rowidNo existing expectation changed. On this branch:
make smokeTest: 0 failures across system SQLite (max and min targets), SQLCipher 3, SQLCipher 4 encrypted, custom SQLite, and SPM.Pull Request Checklist
developmentbranch.make smokeTestterminal command runs without failure.