将串行列添加到大表的最有效方法

Thi*_*yen 12 postgresql performance sequence update

将 BIGSERIAL 列添加到大表(约 3 Bil. 行,约 174Gb)的最快方法是什么?

编辑:

  • 我希望该列是现有行 ( NOT NULL) 的递增值。
  • 我没有设置填充因子(回想起来,这似乎是一个错误的决定)。
  • 我对磁盘空间没有问题,只是希望它尽可能快。

Erw*_*ter 13

有什么问题:

ALTER TABLE foo ADD column bar bigserial;
Run Code Online (Sandbox Code Playgroud)

将自动填充唯一值(从 1 开始)。

如果您希望每个现有行都有一个数字,则必须更新表中的每一行。或者你没有?

如果它不能重用死元组或数据页上的可用空间,该表将膨胀到其大小的两倍。操作的性能可能会从FILLFACTOR低于 100 或只是散布在表上的随机死元组中受益很多。否则,您可能希望在VACUUM FULL ANALYZE之后运行以恢复磁盘空间。不过,这不会很快。

pgstattuple
您可能对此扩展感兴趣。它可以帮助您收集有关表格的统计信息。要了解死元组和可用空间:

每个数据库安装一次扩展:

CREATE EXTENSION pgstattuple;
Run Code Online (Sandbox Code Playgroud)

称呼:

SELECT * FROM pgstattuple('tbl');
Run Code Online (Sandbox Code Playgroud)

选择

如果您有能力创建一个新表,这会破坏依赖的视图、外键、...

创建旧表的空副本:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;
Run Code Online (Sandbox Code Playgroud)

添加 bigserial 列:

ALTER new_tbl ADD column bar bigserial;
Run Code Online (Sandbox Code Playgroud)

从旧表插入数据,自动填充 bigserial:

INSERT INTO new_tbl
SELECT *    --  new column will be filled with default
FROM   old_tbl
ORDER  BY something; -- or don't order if you don't care: faster
Run Code Online (Sandbox Code Playgroud)

INSERT 的 SELECT 中缺少新的 bigserial 列,将自动填充其默认值。您可以拼出所有列并将其添加nextval()SELECT列表中以达到相同的效果。

确保您在新表中获得了所有数据。
添加索引,约束,你在旧表有触发器现在

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;
Run Code Online (Sandbox Code Playgroud)

整体上可能会快一些。这让您拥有一个没有任何膨胀的普通表(和索引)。

您需要可用磁盘空间 - 大约是旧表的大小,具体取决于表的状态 - 作为摆动空间。但是由于表膨胀,您可能需要使用第一种简单方法。同样,详细信息取决于表的状态。

  • 将替代方案包装在单个事务中,这样会快得多。它将避免额外的`fsync`s (3认同)