所以我有一个包含大型数据集的表,并且该表有三列我想删除。
问题是:Postgres 将如何处理它?
它会遍历每个条目还是仅更新映射信息而无需太多开销?ALTER TABLE
在这种特殊情况下,我可以制作一个还是应该使用交换表?
而且,如果有任何区别,所有三列都有固定长度(两个整数和一个数字)。
很抱歉,如果它已经被问过,但谷歌找不到任何相关的问题/文章......
所以我有一个包含大型数据集的表,并且该表有三列我想删除。
问题是:Postgres 将如何处理它?
它会遍历每个条目还是仅更新映射信息而无需太多开销?ALTER TABLE
在这种特殊情况下,我可以制作一个还是应该使用交换表?
而且,如果有任何区别,所有三列都有固定长度(两个整数和一个数字)。
很抱歉,如果它已经被问过,但谷歌找不到任何相关的问题/文章......
ALTER TABLE DROP COLUMN 仅禁用系统表中的列。它非常快,但不会从堆文件中删除数据。您必须稍后执行 VACUUM FULL 以压缩分配的文件空间。所以 ALTER TABLE DROP COLUMN 非常快。而要压缩文件,您必须调用较慢的(带有独占 LOCK)VACUUM FULL。
谷歌可能对这个问题没用,但手册很少失败:
该
DROP COLUMN
表单并未物理删除该列,而只是使其对 SQL 操作不可见。表中的后续插入和更新操作将存储该列的空值。因此,删除列很快,但不会立即减少表的磁盘大小,因为被删除列占用的空间不会被回收。随着现有行的更新,空间将随着时间的推移而被回收。
和:
要强制立即重写表,您可以使用
VACUUM FULL
,CLUSTER
或ALTER TABLE
强制重写的一种形式。这导致表中没有语义上可见的更改,但会删除不再有用的数据。
具体来说,attisdropped
系统目录表中的列pg_attribute
设置为true
。
有轻微的副作用(正如克里斯指出的那样):
更新或新插入的行仍然存储一个不可见的 NULL 值,它强制为每个新行创建一个 NULL 位图,即使可见列中没有 NULL。不影响现有行,因为它们保留原始(现在不可见)列值。
NULL 位图必须足够大以覆盖所有可见和已删除的列。在极端情况下,这可能会扩大 NULL 位图。关于有效尺寸:
删除的列计入允许的最大值(无论如何您都不应该抓取)。
目前(Postgres 13)没有简单的方法可以完全摆脱僵尸列。上面提到的表重写用 NULL 替换了不可见的值(这几乎回收了所有空间),但都没有从系统目录中清除删除的列。甚至没有TRUNCATE
。只有创建一个新表(或转储/恢复周期)才能做到这一点。