43

我想我在某处读到,ALTER TABLE foo ADD COLUMN baz text在 postgres 数据库上运行不会导致读取或写入锁定。设置默认值会导致锁定,但允许 null 默认值会阻止锁定。

不过,我在文档中找不到这个。任何人都可以指出一个地方,明确地说,如果这是真的还是假的?

4

3 回答 3

50

Table-level Locks的文档中提到了不同种类的锁以及何时使用它们 。例如,Postgres 11ALTER TABLE可能会获取SHARE UPDATE EXCLUSIVESHARE ROW EXCLUSIVEACCESS EXCLUSIVE锁。

Postgres 9.1 到 9.3 声称支持上述三个中的两个,但实际上强制Access Exclusive用于该命令的所有变体。这个限制在 Postgres 9.4 中被取消,ADD COLUMN仍然ACCESS EXCLUSIVE是设计使然。

在源代码中检查很容易,因为有一个函数专门用于建立此命令在各种情况下所需的锁定级别:AlterTableGetLockLevelsrc/backend/commands/tablecmds.c.


关于锁的持有时间,一旦获得:

  • 当该列的默认值为 NULL 时,该列的添加应该非常快,因为它不需要表重写:它只是目录中的更新。
  • 当列具有非 NULL 默认值时,它取决于 PostgreSQL 版本:在 11 或更高版本中,不会立即重写所有行,因此它应该与 NULL 情况一样快。但是对于 10 或更早的版本,该表被完全重写,因此根据表的大小,它可能会非常昂贵。
于 2013-10-22T20:02:50.907 回答
31

添加新的空列将在非常短的时间内锁定表,因为不需要重写磁盘上的所有数据。虽然添加具有默认值的列需要 PostgreSQL 制作所有行的新版本并将它们存储在磁盘上。在此期间,表将被锁定。

因此,当您需要将具有默认值的列添加到大表时,建议先添加空值,然后小部分更新所有行。这样,您将避免磁盘上的高负载并允许 autovacuum 完成它的工作,因此您最终不会将表大小加倍。

于 2013-10-22T20:45:42.333 回答
12

http://www.postgresql.org/docs/current/static/sql-altertable.html#AEN57290

“添加具有非空默认值的列或更改现有列的类型将需要重写整个表和索引。”

因此文档仅指定何时不重写表。总会有一个锁,但它会很短,以防表不被重写。

于 2013-10-23T15:02:45.363 回答