R009 · default CAUTION

ALTER COLUMN SET NOT NULL

SET NOT NULL performs a full table scan under AccessExclusiveLock — unless a valid CHECK already proves the constraint.

Why this is a problem

PG 12+ skips the scan if a CHECK (col IS NOT NULL) constraint exists and is VALID. Without it, this is a multi-minute lock on large tables.

Don't do this

ALTER TABLE orders ALTER COLUMN status SET NOT NULL;

Do this instead

-- 1. CHECK constraint NOT VALID (instant)
ALTER TABLE orders ADD CONSTRAINT orders_status_not_null
  CHECK (status IS NOT NULL) NOT VALID;

-- 2. Validate (low-lock)
ALTER TABLE orders VALIDATE CONSTRAINT orders_status_not_null;

-- 3. SET NOT NULL is now fast (PG 12+ uses existing CHECK)
ALTER TABLE orders ALTER COLUMN status SET NOT NULL;
ALTER TABLE orders DROP CONSTRAINT orders_status_not_null;

References

Catch this rule on every PR.

dbivio runs all 10 rules automatically with your real Postgres stats. Install once, get a verdict on every migration PR.

Install on GitHub