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