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


10

将BIGSERIAL列添加到巨大的表(〜3个Bil。行,〜174Gb)中,最快的方法是什么?

编辑:

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

Answers:


12

有什么问题:

ALTER TABLE foo ADD column bar bigserial;

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

如果要为每个现有行都提供一个数字,则必须更新表中的每一行。还是不?

如果表无法重用死元组或数据页上的可用空间,则该表的大小将膨胀到其两倍。FILLFACTOR小于100的随机元组或分布在表上的随机死元组可能会大大提高操作性能。否则,您可能要VACUUM FULL ANALYZE稍后再运行以恢复磁盘空间。不过,这不会很快。

pgstattuple
您可能对此扩展感兴趣。它可以帮助您收集表中的统计信息。要了解死元组和可用空间,请执行以下操作:

每个数据包一次安装扩展程序:

CREATE EXTENSION pgstattuple;

呼叫:

SELECT * FROM pgstattuple('tbl');

另类

如果您有能力创建一个新表,该表会因视图,外键,...而中断。

创建旧表的空副本:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

添加bigserial列:

ALTER new_tbl ADD column bar bigserial;

从旧表中插入数据,自动填充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

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

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

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

总体上可能要快得多。这样就为您提供了一个没有任何膨胀的原始表(和索引)。

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


3
将替代方案包装在单个事务中,这将更快。它将避免额外fsync的错误
Frank Heikens 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.