Relationship · Introduces Risk
Source: Failure Mode·Target: Workload
Summary
Schema migrations on write-heavy transactional tables acquire aggressive locks (AccessExclusiveLock) that block all reads and writes. On a high-traffic table receiving 5,000 writes/second, a migration lock that waits even 1 second queues 5,000 transactions behind it, causing a connection pool exhaustion cascade.
Evidence
- ·ALTER TABLE ... ADD COLUMN NOT NULL with a DEFAULT requires a table rewrite in pre-11 PostgreSQL: blocks entire table
- ·PostgreSQL 11+ allows adding columns with defaults without table rewrite, but locks still propagate
- ·A 1-second lock wait on a 5K writes/second table queues 5,000 transactions: exhausting a 100-connection pool in milliseconds
- ·GitHub's gh-ost and Percona's pt-online-schema-change exist specifically to work around migration locks
- ·CREATE INDEX (without CONCURRENTLY) holds ShareLock: blocks all writes for the duration
Operational Context
- ·Use CREATE INDEX CONCURRENTLY: takes longer but only holds a ShareUpdateExclusiveLock (does not block writes)
- ·Use lock_timeout=100ms to prevent migrations from queuing a backlog of transactions on the locked table
- ·Validate migrations in staging against production-scale data before deploying : lock duration scales with table size
Tradeoffs
- ·Online schema change tools (gh-ost, pg_repack) add operational complexity but eliminate downtime risk
- ·lock_timeout=100ms causes migration to fail rather than block: requires retry logic
- ·{'Zero-downtime migrations require more code': 'add new column → backfill → add constraint → drop old column'}
Evidence grounding
Grounded, 5 supporting itemsSchema migration locking on production OLTP tables is one of the most frequent production incidents documented in PostgreSQL operational guides, GitHub engineering blog, and Braintree/PayPal database teams.