【发布时间】:2017-02-06 14:51:07
【问题描述】:
我想将一列更改为 NOT NULL:
ALTER TABLE "foos" ALTER "bar_id" SET NOT NULL
“foos”表有近 1 000 000 条记录。它的写入量相当低,但相当稳定。阅读量很大。
根据我的经验,像这样将大表中的列更改为 NOT NULL 可能会导致应用停机,大概是因为它会导致 (b) 锁定。
不过,我还没有找到一个很好的解释来证实这一点。
如果是真的,我该怎么做才能避免呢?
编辑:The docs(通过this comment)说:
使用 DEFAULT 子句添加列或更改现有列的类型将需要重写整个表及其索引。
我不确定更改 NULL 是否算作“更改现有列的类型”,但我相信上次看到此问题时我确实在该列上有了索引。
也许删除索引,使列 NOT NULL,然后添加索引会有所改善?
【问题讨论】:
-
在 DBA Stack Exchange 上找到这个:dba.stackexchange.com/questions/66840/… 在我写这篇文章的时候,他们基本上是说没有办法,尽管你可以做其他事情,比如使用 CONSTRAINTs(也建议@a_horse_with_no_name 下面)。
-
看起来其中一个答案由于某种原因被删除了。它指出了the docs 如何说“除非明确指出,否则会持有访问独占锁”。 (并且没有明确指出其他任何内容。)据我所知,这是一个读取和写入的全表锁。该答案还表示将对整个表进行顺序扫描,以确保所有列均为 NULL。我猜这两件事(慢扫描、全表锁)一起解释了问题。
-
在 postgres 11 中这个 cnstraint 已被删除。
-
@dland 谢谢!您的意思是 CONSTRAINT 解决方案不再可能,或者更改为 NOT NULL 不再危险?编辑:可能是后者? “...... PostgreSQL 将重写整个表,这在活动系统中的较大表上可能会导致一系列问题。PostgreSQL 11 在大多数情况下消除了重写表的需要,因此运行 ALTER TABLE .. ADD COLUMN .. DEFAULT 。 . 将非常迅速地执行。” postgresql.org/about/news/1855
-
是的,在第 11 页中,
SET NOT NULL不再需要重写表。如果在指定 NOT NULL 时查询“空”列,引擎将从新系统目录中提取缺少的默认值,从而遵守非空约束。以前,必须用新列上的默认值填充该行,因为没有回退到其他地方查看。他们基本上解决了另一个间接级别的问题。
标签: postgresql