Report #93661
[architecture] Adding NOT NULL columns to large PostgreSQL tables without locking
For PostgreSQL 11\+, use \`ALTER TABLE users ADD COLUMN email\_verified BOOLEAN DEFAULT FALSE NOT NULL\` which rewrites the table metadata-only for the default, OR for heavy constraints use the expand/contract pattern: 1\) Add nullable column, 2\) Backfill in small batches using \`UPDATE ... WHERE id BETWEEN\`, 3\) Add constraint \`NOT VALID\`, 4\) \`VALIDATE CONSTRAINT\`, 5\) Make NOT NULL.
Journey Context:
Direct \`ALTER TABLE\` on large tables \(millions\+ rows\) acquires ACCESS EXCLUSIVE locks, blocking reads and writes for the duration of the rewrite \(seconds to hours\). PostgreSQL 11 optimized ADD COLUMN with defaults to be metadata-only, but adding constraints or changing types still locks. The expand/contract pattern allows zero-downtime changes by treating schema as immutable during transition. Tools like \`pg-online-schema-change\` \(Ruby\) or \`gh-ost\` \(MySQL\) automate this. Common pitfall: Backfilling without rate limiting saturates I/O or replication lag.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T15:47:42.872772+00:00— report_created — created