Database Administration (PostgreSQL)

Migrations Without Downtime

35 دقيقة

Schema changes are the riskiest database operation. Most can be done with no downtime if you know which operations lock tables.

Migrations as code

PandaDev uses Alembic through Flask-Migrate:

flask db migrate -m "add super_admin to users"   # generate from model changes
# REVIEW the generated file: autogenerate misses things
flask db upgrade                                  # apply
flask db downgrade                                # roll back one step

Every migration is committed to Git and runs in the same order everywhere. Never edit a production schema by hand.

Operations and their locks

Operation Safe on a busy table?
Add a nullable column yes, instant
Add a column with a constant default (PG 11+) yes, instant
Add NOT NULL to an existing column scans the table while locked: use the pattern below
Create an index only with CONCURRENTLY
Add a foreign key use NOT VALID, then VALIDATE separately
Change a column's type usually rewrites the table: avoid, add a new column
Rename a column or table instant, but breaks running code: use expand and contract

Always set a lock timeout

A migration waiting for a lock blocks every query queued behind it. Fail fast instead:

SET lock_timeout = '5s';

Adding NOT NULL safely

ALTER TABLE users ADD CONSTRAINT users_country_nn CHECK (country IS NOT NULL) NOT VALID;
-- backfill in batches, then:
ALTER TABLE users VALIDATE CONSTRAINT users_country_nn;   -- no write lock
ALTER TABLE users ALTER COLUMN country SET NOT NULL;      -- PG 12+ uses the valid constraint, no scan
ALTER TABLE users DROP CONSTRAINT users_country_nn;

Expand and contract

To rename fullname to display_name without breaking the running app:

  1. Expand: add display_name (nullable). Deploy code that writes both columns.
  2. Backfill: copy old values in batches of a few thousand rows.
  3. Switch reads: deploy code that reads display_name.
  4. Contract: once nothing uses fullname, drop it in a later release.

Each step is backward compatible with the code running beside it, so deploys and rollbacks are always safe.

Batch backfills

UPDATE users SET display_name = fullname
WHERE id IN (SELECT id FROM users WHERE display_name IS NULL LIMIT 5000);

Repeat until zero rows are updated, pausing briefly between batches. A single huge UPDATE holds locks and creates massive bloat.

Before every production migration

  • [ ] Tested on a recent copy of production data
  • [ ] Timed: you know how long it runs
  • [ ] lock_timeout set
  • [ ] Backup or PITR point confirmed
  • [ ] Rollback plan written

Check yourself

  • Why is a lock timeout essential?
  • Describe the four steps of expand and contract.
  • Why backfill in batches?

يُحفظ تقدّمك في هذا المتصفح فقط.

إرسال للمراجعة (10 نقطة)