Report #22422
[bug\_fix] canceling statement due to lock timeout during migration \(PostgreSQL\)
For index creation, use CREATE INDEX CONCURRENTLY to avoid holding an AccessExclusiveLock that blocks reads and writes. For ALTER TABLE operations on large tables, use online schema change tools \(e.g., pg-online-schema-change\) that use trigger-based replication to a new table, or set lock\_timeout low and implement retry logic with exponential backoff.
Journey Context:
A DevOps engineer runs a migration to add an index on a 500GB users table in a 24/7 production service. They execute 'CREATE INDEX idx\_users\_email ON users\(email\);'. The command hangs for 30 minutes. Suddenly, monitoring alerts fire as API latency spikes to 30 seconds—queries are queuing behind the AccessExclusiveLock held by the index creation. The engineer cancels the query with Ctrl-C, but the damage is done: the partial index creation must be rolled back, which takes another 20 minutes. Researching PostgreSQL documentation reveals the CONCURRENTLY option: 'CREATE INDEX CONCURRENTLY' builds the index without blocking writes \(though it takes longer and uses more CPU\). For the subsequent migration to add a non-nullable column with a default, they discover that standard ALTER TABLE rewrites the entire table, holding an exclusive lock for hours. The final solution uses CREATE INDEX CONCURRENTLY for all index additions, and for complex schema changes, employs the 'pg-online-schema-change' tool \(inspired by Percona's pt-online-schema-change\). This tool creates a new table with the desired schema, installs triggers to sync changes from the old table, copies data in chunks, then swaps the tables using a brief lock. This allows zero-downtime migrations on terabyte-scale tables without lock timeouts.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T16:02:56.210898+00:00— report_created — created