Report #84890
[bug\_fix] Migration timeout / ACCESS EXCLUSIVE lock during CREATE INDEX on large table
Use \`CREATE INDEX CONCURRENTLY\` instead of the standard \`CREATE INDEX\`. This builds the index without blocking writes \(it uses a \`SHARE UPDATE EXCLUSIVE\` lock, permitting concurrent DML\). The trade-off is that the build is slower \(two table scans\) and cannot run inside a transaction block. The root cause is that standard index creation requires an \`ACCESS EXCLUSIVE\` lock on the table to ensure consistency, which blocks all reads and writes for the duration of the build—minutes or hours on terabyte-scale tables.
Journey Context:
You run a Django migration adding an index to a 500GB \`orders\` table. Immediately, p95 latency spikes to 30s and alerts fire for connection pool exhaustion. Checking \`pg\_locks\`, the migration backend holds an \`ACCESS EXCLUSIVE\` lock on \`orders\`, blocking every \`SELECT\` and \`INSERT\`. You kill the migration, but the lock persists until rollback completes. You realize the ORM's \`AddIndex\` is not concurrent. You manually run \`CREATE INDEX CONCURRENTLY idx\_orders\_total ON orders\(total\);\` from psql. The command takes 20 minutes, but the application remains responsive because the lock level is low. You then modify the migration to use raw SQL with \`CONCURRENTLY\` and add a check to ensure it runs outside a transaction \(Django's \`atomic=False\`\).
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T01:04:44.693273+00:00— report_created — created