SQLite Performance Optimizations
This project runs on a Raspberry Pi 3 (1GB RAM) and uses SQLite for both interactive API reads and ETL writes. To reduce lock contention and SD-card I/O pressure, we enforce SQLite PRAGMAs for every new SQLAlchemy connection.
Why This Exists
Section titled “Why This Exists”Without consistent per-connection SQLite settings, mixed read/write workloads can hit database is locked
errors and high fsync overhead.
The backend enforces these settings at connection time in
backend-api/src/dicechess_trainer/database.py using SQLAlchemy engine events.
Enforced PRAGMAs
Section titled “Enforced PRAGMAs”PRAGMA journal_mode=WAL;- Enables concurrent readers during writes.
PRAGMA synchronous=NORMAL;- Reduces fsync calls while keeping a safe durability profile with WAL.
PRAGMA cache_size=-10000;- Caps cache to about 10 MB per connection (negative value is KiB units).
PRAGMA foreign_keys=ON;- Ensures relational integrity checks are active.
Where It Is Configured
Section titled “Where It Is Configured”- Runtime hook:
backend-api/src/dicechess_trainer/database.py - Listener:
@event.listens_for(Engine, "connect")
The listener applies PRAGMAs on each new DBAPI connection. This is important because SQLAlchemy pools can create new connections over time.
Verification
Section titled “Verification”Automated check:
- Test file:
backend-api/tests/test_database_pragmas.py - Assertions:
PRAGMA journal_mode;returnswalPRAGMA foreign_keys;returns1
Manual check against a local DB file (optional):
PRAGMA journal_mode;PRAGMA synchronous;PRAGMA cache_size;PRAGMA foreign_keys;Contributor Notes
Section titled “Contributor Notes”- Prefer changing these values only with a clear benchmark or operational reason.
- Keep docs and
backend-api/tests/test_database_pragmas.pyaligned with runtime behavior. - WAL behavior is meaningful for file-backed SQLite databases; in-memory DBs do not behave the same way.
- For production backup/export steps on the Raspberry Pi, see Backup Production Database.