由于 Postgres 只能在表的末尾添加列,我最终通过在表的末尾添加新列,将它们设置为等于现有列,然后删除原始列来重新排序。
那么,PostgreSQL 对被删除的列释放的内存做了什么?它会自动重用内存,因此单个记录消耗的空间量与以前相同吗?但这需要重写整个表,所以为了避免这种情况,它是否只是在每条记录中保留一堆空白?
由于 Postgres 只能在表的末尾添加列,我最终通过在表的末尾添加新列,将它们设置为等于现有列,然后删除原始列来重新排序。
那么,PostgreSQL 对被删除的列释放的内存做了什么?它会自动重用内存,因此单个记录消耗的空间量与以前相同吗?但这需要重写整个表,所以为了避免这种情况,它是否只是在每条记录中保留一堆空白?
这个问题很老,但是由于两个答案都是错误的或具有误导性,我将添加另一个答案。
VACUUM
当更新一行时,Postgres 会写入一个新的行版本,并且在没有运行的事务可以看到它之后,旧版本最终会被删除。
PlainVACUUM
不会将包含该表的物理文件的磁盘空间返回给系统,除非它在表的物理末端发现完全死块或空块。您需要运行VACUUM FULL
或CLUSTER
积极压缩表并将多余的空间返回给系统。这在正常操作中通常是不希望的。Postgres 可以重用死元组以将新行版本保留在同一数据页上,这有利于性能。
在您的情况下,由于您更新每一行,表的大小加倍(从其最小大小)。建议运行VACUUM FULL
或 CLUSTER
将膨胀返回系统。
两者都在表上使用排他锁。如果这会干扰并发访问,请考虑pg_repack
,它可以在没有排他锁的情况下做同样的事情。
澄清一下:跑步CLUSTER
完全回收了空间。之后不需要(反之亦然)。VACUUM FULL
CLUSTER
更多细节:
从文档:
该
DROP COLUMN
表单并未物理删除该列,而只是使其对 SQL 操作不可见。表中的后续插入和更新操作将存储该列的空值。因此,删除列很快,但不会立即减少表的磁盘大小,因为被删除列占用的空间不会被回收。随着现有行的更新,空间将随着时间的推移而被回收。
您需要执行 aCLUSTER
后跟 aVACUUM FULL
来回收空间。
为什么要“重新排序”?SQL中没有顺序,它没有意义。如果您需要固定顺序,请告诉您的查询您需要什么顺序或使用视图,这就是视图的用途。
磁盘空间将在真空后再次使用,auto_vacuum 将完成这项工作。除非你禁用了这个过程。
您当前的方法将扼杀整体性能(表锁),必须重新创建索引,统计数据会被淘汰等等。最后,您最终会遇到与您一样的情况。那么为什么要努力呢?