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