2010-04-08 49 views
1

由于Postgres只能在表格末尾添加列,所以我最终通过在表格末尾添加新列,将它们设置为等于现有列,然后删除原始列来重新排序。对PostgreSQL中的列重新排序的记录大小有什么影响?

那么,PostgreSQL是如何处理被丢弃列释放的内存的呢?它是否会自动重新使用内存,因此单个记录消耗与以前相同的空间量?但是这需要重写整个表格,所以为了避免这种情况,它是否会在每条记录中留下一堆空白空间?

回答

1

docs

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

您需要先执行CLUSTER后跟VACUUM FULL才能回收空间。

+2

真空FULL如果每行更新将只回收空间,这完全死亡后行清理 - 另有好行没有死列。由于设置新列的UPDATE必须在执行DROP之前发生,因此现在已过时的列占用的空间将不会被它收回。只有该行的原始副本将被清除。 除了完全更新之外,您还可以执行CLUSTER(在PostgreSQL 8.3或更高版本中)或创建表的全新副本(类似于CREATE TABLE AS),然后对名称进行随机洗牌以实际消除死亡空间列。 – 2010-04-10 00:46:26

+0

@Greg:好的一点。 – Quassnoi 2010-04-10 18:21:09

+0

@Summer:'CLUSTER'重写整个表格(加上索引),从而完美地优化它。 'CLUSTER'后面的'VACUUM FULL'是多余的。你可能想要运行'ANALYZE'。这个答案是不正确的(报价除外)。我添加了一个答案来澄清。 – 2015-04-10 18:29:59

1

你为什么“重新订购”?在SQL中没有顺序,它没有建立起来。如果你需要一个固定的订单,告诉你的查询你需要什么顺序或使用一个视图,这是什么意见。

Diskspace将在真空后再次使用,auto_vacuum将完成这项工作。除非你禁用了这个过程。

你目前的方法会杀死整体性能(表锁),索引必须重新创建,统计数据下到厕所等等。最后,你最终会遇到同样的情况。那么为什么这样做呢?

+0

我期待这个来。我喜欢我的专栏,以便像我一样对人类有意义。只要它不占用太多的磁盘空间(在真空满后它不会占用太多空间)。只是个人喜好。 :) – Summer 2010-04-08 17:19:28

+2

您不应该依赖隐式列排序,就像不应该依赖隐式行排序而不使用ORDER BY。这是否意味着您的应用程序使用SELECT *和INSERT INTO表VALUES,而没有字段名?因为那只是要求麻烦。如果您想要特定的列顺序,请使用该顺序创建一个视图。 – MkV 2010-04-09 08:55:18

+0

我需要重新排序,因为将某些列组合起来更简单!我无法相信像Postgres这样基本的东西是不被支持的......课程我不依赖表中列的顺序,但是在设计数据库时它更容易!为什么所有这些linux读者都不明白这一点?!现在人们使用GUI!这是2011年! – Dylan 2011-02-19 12:48:11

1

问题是旧的,但既然这两个答案都是错误或误导,我会再添加一个。

当更新一行时,Postgres写入一个新的行版本,旧的版本最终在VACUUM之后被删除,没有运行的事务可以再看到它。

Plain VACUUM不会从包含表的物理文件向系统返回磁盘空间,除非它在表的物理端找到完全死或空的块。您需要运行VACUUM FULLCLUSTER来积极压缩表格并将多余的空间返回给系统。这在正常操作中通常不是理想的。 Postgres可以重新使用死元组来保持同一数据页面上的新行版本,这有利于性能。

在你的情况,由于你更新每一行,表的大小加倍(从它的最小大小)。建议运行VACUUM FULLCLUSTER将膨胀返回到系统。
两个都在桌子上独占锁。如果干扰并发访问,请考虑pg_repack,这可以在不使用排他锁的情况下执行相同的操作。

澄清:运行CLUSTER完全回收空间。No VACUUM FULL is needed after CLUSTER (and vice versa).

更多细节:

相关问题