Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a column NOT NULL in a large table without locking issues?

Tags:

postgresql

I want to change a column to NOT NULL:

ALTER TABLE "foos" ALTER "bar_id" SET NOT NULL

The "foos" table has almost 1 000 000 records. It does fairly low volumes of writes, but quite constantly. There are a lot of reads.

In my experience, changing a column in a big table to NOT NULL like this can cause downtime in the app, presumably because it leads to (b)locks.

I've yet to find a good explanation corroborating this, though.

And if it is true, what can I do to avoid it?

EDIT: The docs (via this comment) say:

Adding a column with a DEFAULT clause or changing the type of an existing column will require the entire table and its indexes to be rewritten.

I'm not sure if changing NULL counts as "changing the type of an existing column", but I believe I did have an index on the column the last time I saw this issue.

Perhaps removing the index, making the column NOT NULL, and then adding the index back would improve things?

like image 539
Henrik N Avatar asked Feb 06 '17 14:02

Henrik N


People also ask

How do you make a column not a null in a view?

You can make that column in your view non-nullable by replacing it with ISNULL(CONVERT(BIT,U. RETIRED),0) AS Retired. If U. RETIRED was not null to start, it functionally doesn't change anything except the column in the view.

Which column in a table has always the not null constraint?

Based on the SQL standard, PRIMARY KEY should always imply NOT NULL . However, SQLite allows NULL values in the PRIMARY KEY column except that a column is INTEGER PRIMARY KEY column or the table is a WITHOUT ROWID table or the column is defined as a NOT NULL column.

How do you make an existing column NOT NULL in PostgreSQL?

To add a not-null constraint, which cannot be written as a table constraint, use this syntax: ALTER TABLE products ALTER COLUMN product_no SET NOT NULL; The constraint will be checked immediately, so the table data must satisfy the constraint before it can be added.


1 Answers

I think you can do that using a check constraint rather then set not null.

ALTER TABLE foos 
     add constraint id_not_null check (bar_id is not null) not valid;

This will still require an ACCESS EXCLUSIVE lock on the table, but it is very quick because Postgres doesn't validate the constraint (so it doesn't have to scan the entire table). This will already make sure that new rows (or changed rows) can not put a null value into that column

Then (after committing the alter table!) you can do:

alter table foos validate constraint id_not_null;

Which does not require an ACCESS EXCLUSIVE lock and still allows access to the table.

like image 149
a_horse_with_no_name Avatar answered Sep 29 '22 05:09

a_horse_with_no_name