Lesson 13 · Indexes
Index trade-offs
Indexes aren't free — the cost, and why a present index sometimes isn't used.
Your win: explain the write cost of indexes, decide when not to add one, and diagnose why an existing index gets ignored — a top interview question.
Indexes cost writes and storage
Every index must be kept in sync: an INSERT, and an UPDATE of an
indexed column, must update every affected index too — more work per write, more WAL
(Lesson 8), more disk.1 (The HOT
optimisation from Lesson 9 skips index updates when no indexed column changed — one reason
our soft-delete deleted_at updates stay cheap.)
Why a present index isn't used
Interviewers love this. An index exists but EXPLAIN shows a seq scan —
common reasons:2
| Reason | Fix |
|---|---|
| Query returns most of the table → seq scan is cheaper | nothing — the planner is right |
| Stale statistics → planner misestimates | ANALYZE (autovacuum usually) |
A function wraps the column: WHERE lower(email) = … | an expression index (Lesson 12) |
Type mismatch (e.g. text col vs int literal) | cast correctly / fix the param type |
WHERE lacks the composite index's leading column | reorder the index or the query |
CONCURRENTLY IF NOT EXISTS
(notificationmgmt/1026,1028) — CONCURRENTLY
builds without locking writes on a big live table (it's slower and can't run in a
transaction, but it doesn't block production). And notice the team indexes
deliberately — resource_path, FKs, real search columns — not every
column. That restraint is the lesson.
Use The Index, Luke! — "Why isn't the database using my index?" + CREATE INDEX
Winand's diagnosis of ignored indexes; the docs on CONCURRENTLY and index
maintenance cost.
→ use-the-index-luke.com
→ postgresql.org/docs — CREATE INDEX
Check yourself (from memory)
Q1. Every extra index makes ___ slower.
Q2. An index is a poor choice on a column that is…
Q3. A present index may be ignored if…
WHERE lower(email) = … can't use a plain
email index — you'd need an expression index. (Also: low selectivity, stale
stats, type mismatch, wrong composite prefix.)
ANALYZE), a function wraps the
column (needs an expression index), types don't match, or the WHERE omits the
composite index's leading column. Build big ones CONCURRENTLY to avoid
locking writes.