SQLite query optimization.

EXPLAIN QUERY PLAN

EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = 'x';

Look for:

  • SEARCH ... USING INDEX (good).
  • SCAN ... (bad on big tables).

ANALYZE

ANALYZE;
ANALYZE users;
PRAGMA analysis_limit = 1000;

Helps optimizer pick indexes.

VACUUM

VACUUM;
PRAGMA auto_vacuum = INCREMENTAL;
PRAGMA incremental_vacuum(100);

Reclaim space after big deletes.

Optimize PRAGMA

PRAGMA optimize;

Run periodically; auto-runs ANALYZE on changed tables.

Indexes

See schema cheatsheet. Most queries should use index.

Covering indexes

CREATE INDEX idx_cover ON users(status, name);
SELECT name FROM users WHERE status = 'x';   -- index-only

Materialize CTEs

WITH expensive AS MATERIALIZED (
    SELECT ... FROM huge_table WHERE ...
)
SELECT * FROM expensive WHERE ...;

Prepared statements

cursor.execute("INSERT INTO users (name) VALUES (?)", (name,))

Reuses parsed plan. Much faster in loops.

Bulk insert

cursor.executemany("INSERT INTO users (name) VALUES (?)", data)
# Or
with conn:
    for row in rows:
        conn.execute("...", row)

Wrap in transaction for 100x speedup.

Pagination

SELECT * FROM users WHERE id > ? ORDER BY id LIMIT 20;

Cursor-based; faster than OFFSET for big tables.

SQLite cache

PRAGMA cache_size = -64000;        -- 64MB negative = KB; positive = pages

mmap

PRAGMA mmap_size = 268435456;       -- 256MB

Memory-map DB file. Faster reads.

temp_store

PRAGMA temp_store = MEMORY;

Temp tables in RAM.

Statement timing

.timer ON
SELECT ...

Common mistakes

  • No index on join column.
  • LIKE ‘%x’ (no prefix → no index).
  • Big OFFSET pagination.
  • Many small inserts without transaction.
  • COUNT(*) on huge table.

Read this next

If you want my SQLite perf checklist, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .