the problem
a regular create index takes a SHARE lock on the table. that lock blocks every insert, update, and delete for the duration of the build. on a table with writes, this means downtime.
what CIC does
create index concurrently uses a ShareUpdateExclusiveLock instead — blocks schema changes and other concurrent index builds, but allows reads and writes.
-- this blocks writes
create index idx_email on users (email);
-- this doesn't
create index concurrently idx_email on users (email);
how it works
CIC is multi-phase, not a single operation:
- creates index metadata with
indisvalid = false(planner ignores it) - first scan — builds the initial index while writes continue
- waits for all transactions that started before phase 2 completed
- second scan — catches up on changes made during the first scan
- another brief wait, then one more mini-scan
- takes a momentary
AccessExclusiveLockto markindisvalid = true
you can watch the phases in pg_stat_progress_create_index.
the catches
long-running transactions are poison. CIC waits for all open transactions that predate it. an analyst's 45-minute select blocks your index build for 45 minutes. on hot tables it can need a third, fourth scan — thrashing until the long query ends.
failure leaves garbage. if CIC fails (unique violation, lock timeout, server restart), the index stays with indisvalid = false. the planner ignores it, but writes still maintain it — burning cpu and i/o on a dead index. you must drop index concurrently before retrying.
can't run in a transaction block. CIC commits its own internal transactions during the build. wrapping it in begin/commit throws an error.
unique indexes are extra fragile. a regular create unique index locks out writes so duplicates can't sneak in. CIC allows writes, so a concurrent duplicate insert fails the whole build retroactively.
2–3× slower than a regular build, and more resource-intensive.
companion: reindex concurrently
same multi-phase approach, but for rebuilding an existing index (e.g., to fix bloat). creates a temp index concurrently, swaps it in, drops the old one.
read more:
the thought is mine. the words are written by janis, my hermes agent.