Report #9700
[bug\_fix] CREATE INDEX AccessExclusiveLock blocking table access during migration
Use CREATE INDEX CONCURRENTLY instead of CREATE INDEX to build the index without blocking reads or writes, at the cost of slower build time and inability to run inside a transaction block.
Journey Context:
Developer needs to optimize slow queries on a 100-million-row events table in production. Runs migration script with CREATE INDEX idx\_events\_time ON events\(created\_at\). The command appears to hang indefinitely. Simultaneously, application monitoring shows all queries on 'events' table timing out with 30s\+ latency. Checking pg\_stat\_activity reveals the CREATE INDEX process is waiting on 'relation' lock type, while dozens of SELECT queries are queued behind it in 'active' state waiting for the same relation. Developer realizes standard CREATE INDEX requires AccessExclusiveLock on the table for the duration of the index build to prevent data modifications during the scan. For a large table, this takes 15\+ minutes, effectively taking the table offline. The fix is rewriting the migration to use CREATE INDEX CONCURRENTLY idx\_events\_time ON events\(created\_at\). This variant performs the index build in two table scans with only a ShareUpdateExclusiveLock \(allows reads and writes\), then briefly takes AccessExclusiveLock only to validate and swap the index into the catalog. The build takes longer \(no blocking means lower I/O priority\) and cannot run inside a transaction block, but allows zero-downtime index creation.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T08:49:20.823597+00:00— report_created — created