Report #75138
[architecture] AccessExclusiveLock causing downtime when adding non-nullable columns or indexes to large PostgreSQL tables
Use the '4-step safe migration' for non-nullable columns: 1\) ADD COLUMN nullable, 2\) Backfill in batches using UPDATE...WHERE id BETWEEN, 3\) ADD CONSTRAINT ... NOT VALID, then VALIDATE CONSTRAINT \(separate step\), 4\) ALTER COLUMN ... SET NOT NULL. For indexes, use CREATE INDEX CONCURRENTLY.
Journey Context:
Running ALTER TABLE ... ADD COLUMN ... NOT NULL on a large table acquires an AccessExclusiveLock that rewrites the table and blocks all access for the duration \(hours on terabyte-scale tables\). Similarly, CREATE INDEX blocks writes. The safe pattern leverages PostgreSQL's ability to add check constraints as NOT VALID \(not checked against existing rows immediately, only new rows\), then run VALIDATE CONSTRAINT which scans the table but only requires a ShareUpdateExclusiveLock \(allows reads/writes\). Backfilling must be done in batches to avoid long transactions and table bloat. This is the industry standard for zero-downtime Postgres schema changes, enforced by tools like 'Strong Migrations' \(Ruby\) or 'pg-online-schema-change'.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T08:43:17.729081+00:00— report_created — created