我想我在某处读到,ALTER TABLE foo ADD COLUMN baz text
在 postgres 数据库上运行不会导致读取或写入锁定。设置默认值会导致锁定,但允许 null 默认值会阻止锁定。
不过,我在文档中找不到这个。任何人都可以指出一个地方,明确地说,如果这是真的还是假的?
我想我在某处读到,ALTER TABLE foo ADD COLUMN baz text
在 postgres 数据库上运行不会导致读取或写入锁定。设置默认值会导致锁定,但允许 null 默认值会阻止锁定。
不过,我在文档中找不到这个。任何人都可以指出一个地方,明确地说,如果这是真的还是假的?
Table-level Locks的文档中提到了不同种类的锁以及何时使用它们
。例如,Postgres 11ALTER TABLE
可能会获取SHARE UPDATE EXCLUSIVE
、SHARE ROW EXCLUSIVE
或ACCESS EXCLUSIVE
锁。
Postgres 9.1 到 9.3 声称支持上述三个中的两个,但实际上强制Access Exclusive
用于该命令的所有变体。这个限制在 Postgres 9.4 中被取消,但ADD COLUMN
仍然ACCESS EXCLUSIVE
是设计使然。
在源代码中检查很容易,因为有一个函数专门用于建立此命令在各种情况下所需的锁定级别:AlterTableGetLockLevel
在src/backend/commands/tablecmds.c
.
关于锁的持有时间,一旦获得:
添加新的空列将在非常短的时间内锁定表,因为不需要重写磁盘上的所有数据。虽然添加具有默认值的列需要 PostgreSQL 制作所有行的新版本并将它们存储在磁盘上。在此期间,表将被锁定。
因此,当您需要将具有默认值的列添加到大表时,建议先添加空值,然后小部分更新所有行。这样,您将避免磁盘上的高负载并允许 autovacuum 完成它的工作,因此您最终不会将表大小加倍。
http://www.postgresql.org/docs/current/static/sql-altertable.html#AEN57290
“添加具有非空默认值的列或更改现有列的类型将需要重写整个表和索引。”
因此文档仅指定何时不重写表。总会有一个锁,但它会很短,以防表不被重写。