更新为单个新列时,数据库大小会翻倍

时间:2014-07-07 09:43:17

标签: postgresql

我有一个相当简单的表,用于为Web地图应用程序驱动磁贴处理。

   Column      |    Type                  |    Modifiers                        
---------------+--------------------------+---------------------------------------------------------
 id            | integer                  | not null default
                                             nextval('wmts_tiles_id_seq'::regclass)
 tile_matrix   | integer                  | 
 rowx          | integer                  | 
 coly          | integer                  | 
 geom          | geometry(Geometry,27700) | 
 processed     | smallint                 | 

Indexes:
   "wmts_tiles_pkey" PRIMARY KEY, btree (id)
   "wmts_tiles_wmts_tile_matrix_x_y" UNIQUE CONSTRAINT, btree (tile_matrix, rowx, coly)
   "ix_spatial_wmts_tiles" gist (geom)
   "ix_tile_matrix_processed" btree (tile_matrix, processed)

具有各种索引(一个空间)和如图所示的constaints。该表有2.4亿行,pg_relation_size和pg_total_relation_size表示该表为66 GB,其中一半是索引,一半是数据。

我添加了一个日期列,然后运行了一个更新来填充它,

alter database wmts_tiles add column currency_date date;
update wmts_tiles set currency_date = '2014-05-01'

此后,大小达到133 GB,即它增加了一倍。一旦我在桌面上运行 VACUUM FULL ,大小缩小到67 GB,即比以前大1GB,这是你在添加2.4亿行4字节字段后所期望的(日期) )。

据我所知,表中经常会有相当比例的死行,其中发生了大量的插入和删除操作,但为什么在一次更新下表的大小会翻倍并且我可以做些什么来防止这个?请注意,此更新是唯一正在运行的事务,并且该表刚刚被转储并重新创建,因此数据页和索引在更新之前处于紧凑状态。

编辑:我已经看到了这个问题,Why does my postgres table get much bigger under update?我明白,虽然表格正在更新以支持MVCC,但表格需要重写,我不明白为什么它会停留两次大小,直到我明确地运行VACUUM FULL。

1 个答案:

答案 0 :(得分:9)

this prior question涵盖了大部分内容。

它没有缩小的原因是PostgreSQL不知道你想要它。分配磁盘空间(增长表)然后重复释放(缩小表)是低效的。 PostgreSQL更喜欢扩展一个表,然后保留磁盘空间,将其标记为空并准备好重复使用。

不仅分配和发布周期效率低下,而且OS也只允许在文件 * 的末尾释放空间。因此,PostgreSQL必须将文件末尾的所有行移动到开始时现在可用空间,这是您在更新时可以写入的唯一位置。它不能这样做,因为在提交更新事务之前它无法覆盖任何旧数据。

如果您知道不再需要空间,可以使用VACUUM FULL压缩表并释放空间。

autovacuum没有定期完成真空,部分原因是如果表必须再次扩展,可能会对性能造成很大的影响,部分原因是因为真空充满了I / O密集型(所以它会减慢所有其他的速度) )部分原因是vacuum full需要access exclusive锁,以防止对表的任何并发访问。 PostgreSQL需要一个增量表重新打包命令/功能,它还没有,因为这可以通过autovacuum实现。欢迎补丁......虽然这部分代码非常复杂,但正确的做法并不适合初学者。


* 是的,我知道您可以将文件中的大区域标记为某些平台上的稀疏区域。随意提交PostgreSQL补丁。实际上你还是必须压缩,因为你没有在表中找到带有空闲页面的大区域。另外,您必须处理页眉。