首先答案是: 会锁表,且获得的是ACCESS EXCLUSIVE锁,但是不同情况下,锁的持有时间会不同。
当列的默认值为NULL时,该列的添加应该非常快,因为它不需要重写表:它只是系统表中的更新。
当列具有非NULL的默认值时,它取决于PostgreSQL版本: 在11.0及之后的版本,不会立即重写所有的行,所以它应该和NULL的情况一样快。但是对于版本10或更早的表,它是完全重写的,因此根据表的大小,它可能非常昂贵。
第一种情况,当列的默认值是null时,即
ALTER TABLE users ADD COLUMN score int;
这个操作很快,新列的信息被添加到system catolog中,而不需要rewrite table。
第二种情况,当列具有非null的默认值时,即
ALTER TABLE users ADD COLUMN score int NOT NULL DEFAULT 0;
关于上面提到的“在11.0及之后的版本,不会立即重写所有的行”, 这一点我们可以看11.0的release note。
参考:https://www.postgresql.org/docs/11/release-11.html
它里面有这样的一段话:
Allow ALTER TABLE to add a column with a non-null default without doing a table rewrite (Andrew Dunstan, Serge Rielau) This is enabled when the default value is a constant.
https://www.postgresql.org/docs/11/release-11.html
允许Alter Table添加非空默认列而不重写表,当默认值为常量时启用此功能。
问题
1、怎么理解重写表?
当添加带有默认值的列时,PostgreSQL需要创建所有行的新版本并将它们存储在磁盘上。
2、11.0是怎么实现这一点的?
pg_attribute中新增了两个字段:atthasmissing和attmissingval。注:pg_attribute是一个系统表,该系统表存储所有表的字段信息,数据库中每个表的每个字段在pg_attribute表中都有一行记录。
在ALTER TABLE时,当新增stable或immutable表达式(非volatile)作为默认值时,即评估表达式的值作为常量,存入新增列在pg_attribute元数据中的attmissingval字段中,同时将atthasmissing标记为true。
注:stable、immutable、volatile是pg的函数稳定性状态。
atthasmissing:当缺少默认值时设置为true。
attmissingval:包含缺失的值。
当扫描返回行时,它们检查这些新字段并在适当的地方返回缺失的值(即atthasmissing)。插入到表中的新行在创建时选择默认值,因此在返回其内容时不需要检查athasmissing。
3、测试一下11.0的情况。
a.创建测试表,新增若干数据。
create unlogged table t_table(id int, info text);
b.添加测试数据。
insert into t_table select generate_series(1,1000000),repeat(md5(random()::text),10);
c.添加非空默认列
alter table t_table add column c1 text default 'test';

d.查看pg_attribute。
select * from pg_attribute where attrelid='t_table'::regclass and attname='c1';

可以看到atthasmissing=t, attmissingval为test。
参考:https://stackoverflow.com/questions/19525083/does-adding-a-null-column-to-a-postgres-table-cause-a-lock
https://github.com/postgres/postgres/commit/16828d5c0273b4fe5f10f42588005f16b415b2d8
https://billtian.github.io/digoal.blog/2018/05/18/01.html
https://dataegret.com/2018/03/waiting-for-postgresql-11-pain-free-add-column-with-non-null-defaults/




