Add new column without table lock?

眉间皱痕 提交于 2019-12-01 06:50:16
Erwin Brandstetter

Updating in PostgreSQL means writing a new version of the row. Your question does not provide all the information, but that probably means writing millions of new rows.

If your data model and available disk space allow for it, CREATE a new table in the background and then, in one transaction: DROP the old table, RENAME the new one.
Details and caveats in this related later answer on dba.SE.

Also, if a major proportion of the table is affected, remove all indexes before doing the mass UPDATE, because all indexes have to be updated too. It is faster to delete them and recreate them after the mass UPDATE is done.

And finally, while creating the new table in the background: Apply all changes at once, or you create multiple updated versions of the affected rows.

Disclaimer: Adding a new column without DEFAULT (= DEFAULT NULL) will not normally create a new row and is very cheap per se. Adding values to it creates new rows.
Details in the maunal.

If you cannot remove the original table because of constraints, another fast way is to build a temporary table, TRUNCATE the original one and mass INSERT the new rows - sorted, if that helps performance. All in one transaction. Something like this:

BEGIN

SET temp_buffers = 1000MB;  -- or whatever you can spare temporarily

CREATE TEMP TABLE tmp AS
SELECT * FROM tbl LIMIT 0; -- copy layout of table

ALTER TABLE tmp ADD column delta boolean; -- NOT DEFAULT

INSERT INTO tmp (col1, col2, ... , delta)
SELECT col1, col2, ... , FALSE
FROM   tbl;                -- copy existing rows plus new value
-- ORDER BY ???

-- DROP all indexes here

TRUNCATE tbl;              -- empty table - truncate is super fast

ALTER TABLE tbl ADD column delta boolean DEFAULT FALSE; -- NOT NULL?

INSERT INTO tbl
SELECT * FROM tmp;         -- insert back surviving rows.

-- recreate all indexes here

COMMIT;

You could add another table with the one column, there won't be any such long locks. Of course there should be another column, a foreign key to the first column.

For the indexes, you could use "CREATE INDEX CONCURRENTLY", it doesn't use too heavy locks on this table http://www.postgresql.org/docs/9.1/static/sql-createindex.html.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!