[11.x] Add ability to configure SQLite busy_timeout
, journal_mode
, and synchronous
pragmas
#52052
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.
This PR adds optional
busy_timeout
,journal_mode
, andsynchronous
configuration options to allow setting the corresponding pragmas on SQLite database connections. Together, these three configuration options can improve SQLite's performance enormously.Background
This SQLite configuration:
is becoming the widely recommended default for modern apps because it is orders of magnitude faster than the default setup and far less prone to
SQLITE_BUSY
errors.journal_mode
configures how transactions are implemented. The default setting,DELETE
, uses a rollback journal. Since SQLite 3.7 aWAL
mode is available that uses a write ahead log, which is significantly faster and allows concurrent database reads and writes in more scenarios.busy_timeout
configures how long SQLite will wait when a table is locked before returning aSQLITE_BUSY
error. The default is0
, which means any attempted concurrent writes will fail immediately. Setting it to a positive integer will make SQLite wait that many milliseconds if the database is locked, which in most cases means that operations will complete with a negligible delay instead of erroring.synchronous
configures how often SQLite flushes the contents of the database to the disk. The default,FULL
, writes data to disk more or less immediately when it changes. TheNORMAL
mode syncs data when necessary but less often, and in combination with WAL mode is much faster, fully consistent, and highly durable.NORMAL
is SQLite's recommended setting when used with WAL mode.Rails and Django both currently support some or all of this functionality. They both have a
timeout
configuration option, Rails 7.1 defaults to WAL mode and NORMAL, and Django 5.1 (releasing in August) is going to add configuration fields for setting transaction modes and other custom pragmas:More info:
Implementation
I based this on the existing code for setting the
foreign_keys
pragma, it works exactly the same way except that the new options accept custom values instead of just being on or off.busy_timeout
andsynchronous
are per-connection settings and have to be set every time Laravel connects to a SQLite database (like the existingforeign_keys
pragma), so it makes sense to store them in the config likeforeign_keys
.journal_mode
is a persistent setting and technically only has to be set once, but the implementation is much simpler and more consistent if we just set it on every connection too.The new configuration options all default to
null
so that existing apps will be completely unaffected by this change.Alternatives
How I'm currently doing this:
Future Scope
I'm going to work on a PR for immediate transactions too, which also combine really well with these settings but will have to be implemented differently.