postgresql
PostgreSQL NOT NULL can be added without locking
Dec 10, 2024There’s bit of an interesting rabbit hole with NOT NULL constraints vs locking up your DB.
It starts with “is a NOT NULL check contraint worse than a NOT NULL”?
The docs hint at some difference: https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-NOT-NULL
Which points to https://dba.stackexchange.com/questions/66840/add-not-null-constraint-to-large-table-without-table-scan
Which finally points to https://dba.stackexchange.com/questions/267947/how-can-i-set-a-column-to-not-null-without-locking-the-table-during-a-table-scan/268128#268128
The big problem is adding a NOT NULL constraint can badly lock up the table and other sessions.
Using a constraint with NOT VALID
and then validating later is a work around.
There’s a third step you can do: add a NOT NULL
after this an PostgreSQL will do a no-lock update.
First add the constraint:
-- short-time exclusive lock
alter table foos
add constraint foos_not_null
check (bar1 is not null) not valid;
Next validate it:
-- seqscan, but without exclusive lock, concurrent sessions can read/write
alter table foos validate constraint foos_not_null;
Finally add not null and drop constraint:
-- exclusive lock, but foos_not_null proves: there is no NULL in this column
-- so this alter table would be fast
alter table foos alter column bar1 set not null;
-- not needed anymore
alter table foos drop constraint foos_not_null;
There is also an approach of adding a NOT NULL with a default value, PostgreSQL optimizes this case: https://brandur.org/postgres-default
ALTER TABLE users
ADD COLUMN credits bigint NOT NULL DEFAULT 0;