FDEBench Join us live

Q
145 / 159

General design

Adding a nullable column to a large Postgres table takes production down. The team assumes Postgres is rewriting every row. They are wrong. What is actually happening, and how do you make migrations safe?

question bank FDEBench bank

01
Sketch

Reference sketch

A short answer key carried over from the source. Not yet a graded rubric.

1. Correct the assumption: adding a nullable column (and, in modern Postgres, one with a constant default) is a catalogue-only change that completes in milliseconds. 2. Locate the real cause: ALTER TABLE needs an ACCESS EXCLUSIVE lock, and if a long-running query holds a conflicting lock, the ALTER waits in the lock queue — and every subsequent read and write queues behind it. 3. Emphasise the cascade: the outage comes from the queue, not the DDL, which is why the statement itself looks instant in staging. 4. Set a short lock_timeout (one to two seconds) on the migration session so a failed acquisition aborts harmlessly instead of blocking traffic. 5. Make the migration tool retry with backoff until a quiet lock window opens. 6. Kill or bound long-running queries first, and set statement_timeout on analytics roles so they cannot hold the queue hostage. 7. Use the expand-migrate-contract pattern for anything beyond an additive column: add the new column, backfill in batches, dual-write, switch reads, then drop the old one in a later release. 8. Build indexes CONCURRENTLY and add constraints as NOT VALID then VALIDATE, to avoid long exclusive locks. 9. Note why staging does not catch this: staging lacks the concurrent long-running query, so the lock queue never forms.

—