PostgreSQL ADD COLUMN DEFAULT NULL锁和性能

时间:2017-12-08 07:24:09

标签: postgresql

我的PostgreSQL 9.6数据库中有一个表,有300万行。该表已经有一个空位图(它还有另外两个DEFAULT NULL字段)。我想在这个表中添加一个新的布尔可空列。我坚持这两个陈述之间的区别:

ALTER TABLE my_table ADD COLUMN my_column BOOLEAN;
ALTER TABLE my_table ADD COLUMN my_column BOOLEAN DEFAULT NULL;

我认为这些陈述没有区别,但是:

  1. 我在文档中找不到任何证据。文档告诉我们为新列提供DEFAULT值会使PostgreSQL重写所有元组,但我不认为这种情况是正确的,因为默认值为NULL
  2. 我对这个表的副本进行了一些测试,第一个语句(没有DEFAULT NULL)花费的时间比第二个多一点。我不明白为什么。
  3. 我的问题是:

    1. PostgreSQL会对这两个语句使用相同的锁类型(ACCESS EXCLUSIVE)吗?
    2. 如果我使用NULL,PostgreSQL是否会重写所有元组以向其中添加DEFAULT NULL值?
    3. 这两个陈述之间有什么区别吗?

2 个答案:

答案 0 :(得分:14)

第2点 Vao Tsun 的回应存在问题。

如果使用ALTER TABLE my_table ADD COLUMN my_column BOOLEAN;,它将不会重写所有元组,只会改变元数据。

但是如果你使用ALTER TABLE my_table ADD COLUMN my_column BOOLEAN DEFAULT NULL,它将重写所有元组,并且它将在长桌上持续使用。

文档本身告诉了这一点。

  

使用ADD COLUMN添加列时,表中的所有现有行都使用列的默认值进行初始化(如果未指定DEFAULT子句,则为NULL)。 如果没有DEFAULT子句,这只是元数据更改,不需要立即更新表的数据;相反,在读数时提供了添加的NULL值。

这告诉我们如果有一个DEFAULT子句,即使它是NULL,它也会重写所有元组。

这是由于更新子句的性能问题。如果你需要对一个没有重写的元组进行更新,它需要将元组移动到另一个磁盘空间,耗费更多时间。

我在Postgresql 9.6 上测试了这个,当我不得不在一个有3亿多元组的表上添加一列时。没有DEFAULT NULL它持续了11毫秒,而DEFAULT NULL它持续了超过30分钟。

答案 1 :(得分:3)

https://www.postgresql.org/docs/current/static/sql-altertable.html

  1. 是 - 同样ACCESS EXCLUSIVE,没有DEFAULT NULL的例外或没有提到DEFAULT(统计信息,“选项”,约束,群集需要不那么严格我想,但不是添加列)
  2.   

    请注意,每个子表单所需的锁定级别可能不同。一个   除非明确说明,否则将保持ACCESS EXCLUSIVE锁定。当多个   列出了子命令,锁定将是最严格的   任何子命令都需要。

    1. 否 - 它宁愿在选择
    2. 上附加NULL
        

      使用ADD COLUMN添加列时,表中的所有现有行   使用列的默认值初始化(如果没有DEFAULT,则为NULL)   指定的子句)。如果没有DEFAULT子句,这只是一个   元数据更改,不需要立即更新   表的数据;相反,在读数时提供了添加的NULL值。

      1. 不 - 没有区别AFAIK。只是元数据在两种情况下都会发生变化(因为我认为这是用不同语义表达的一种情况)
      2. 编辑 - 演示:

        db=# create table so(i int);
        CREATE TABLE
        Time: 9.498 ms
        db=# insert into so select generate_series(1,10*1000*1000);
        INSERT 0 10000000
        Time: 13899.190 ms
        db=# alter table so add column nd BOOLEAN;
        ALTER TABLE
        Time: 1025.178 ms
        db=# alter table so add column dn BOOLEAN default null;
        ALTER TABLE
        Time: 13.849 ms
        db=# alter table so add column dnn BOOLEAN default true;
        ALTER TABLE
        Time: 14988.450 ms
        db=# select version();
                                                            version
        ----------------------------------------------------------------------------------------------------------------
         PostgreSQL 9.6.1 on x86_64-apple-darwin15.6.0, compiled by Apple LLVM version 8.0.0 (clang-800.0.42.1), 64-bit
        (1 row)
        

        最后为了避免猜测它是特定于数据类型的:

        db=# alter table so add column t text;
        ALTER TABLE
        Time: 25.831 ms
        db=# alter table so add column tn text default null;
        ALTER TABLE
        Time: 13.798 ms
        db=# alter table so add column tnn text default 'null';
        ALTER TABLE
        Time: 15440.318 ms