44

所以我有一个包含大型数据集的表,并且该表有三列我想删除。
问题是:Postgres 将如何处理它?

它会遍历每个条目还是仅更新映射信息而无需太多开销?ALTER TABLE在这种特殊情况下,我可以制作一个还是应该使用交换表?

而且,如果有任何区别,所有三列都有固定长度(两个整数和一个数字)。

很抱歉,如果它已经被问过,但谷歌找不到任何相关的问题/文章......

4

2 回答 2

57

ALTER TABLE DROP COLUMN 仅禁用系统表中的列。它非常快,但不会从堆文件中删除数据。您必须稍后执行 VACUUM FULL 以压缩分配的文件空间。所以 ALTER TABLE DROP COLUMN 非常快。而要压缩文件,您必须调用较慢的(带有独占 LOCK)VACUUM FULL。

于 2013-03-29T08:59:56.427 回答
50

谷歌可能对这个问题没用,但手册很少失败

DROP COLUMN表单并未物理删除该列,而只是使其对 SQL 操作不可见。表中的后续插入和更新操作将存储该列的空值。因此,删除列很快,但不会立即减少表的磁盘大小,因为被删除列占用的空间不会被回收。随着现有行的更新,空间将随着时间的推移而被回收。

和:

要强制立即重写表,您可以使用VACUUM FULL, CLUSTERALTER TABLE强制重写的一种形式。这导致表中没有语义上可见的更改,但会删除不再有用的数据。

具体来说,attisdropped系统目录表中的列pg_attribute设置为true

副作用

有轻微的副作用(正如克里斯指出的那样):

  • 更新或新插入的行仍然存储一个不可见的 NULL 值,它强制为每个新行创建一个 NULL 位图,即使可见列中没有 NULL。不影响现有行,因为它们保留原始(现在不可见)列值。

  • NULL 位图必须足够大以覆盖所有可见已删除的列。在极端情况下,这可能会扩大 NULL 位图。关于有效尺寸:

  • 删除的列计入允许的最大值(无论如何您都不应该抓取)。

  • 目前(Postgres 13)没有简单的方法可以完全摆脱僵尸列。上面提到的表重写用 NULL 替换了不可见的值(这几乎回收了所有空间),但都没有从系统目录中清除删除的列。甚至没有TRUNCATE。只有创建一个新表(或转储/恢复周期)才能做到这一点。

于 2013-03-29T09:01:17.733 回答