吐司表生长失控-FULLVAC无效


9

最近,我已经将PostgreSQL 8.2.11服务器升级到8.4,以便利用自动清理功能并与30台其他PGSQL服务器保持一致。这是由管理硬件的独立IT小组完成的,因此在其他任何升级方面我们没有太多选择(暂时不会看到9+)。该服务器存在于非常封闭的环境(隔离的网络,有限的root特权)中,并在RHEL5.5(i686)上运行。升级后,数据库每天不断增长,达到5-6 GB。通常,数据库总体上约为20GB;目前,它约为89GB。我们还有其他几个服务器,它们运行等效的数据库,并实际上通过第3方应用程序将记录彼此同步(其中一个我无法访问内部工作)。其他数据库大约应该是20GB。

运行下面的SQL,很明显特定表,尤其是TOAST表存在问题。

SELECT nspname || '.' || relname AS "relation",
    pg_size_pretty(pg_relation_size(C.oid)) AS "size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
  ORDER BY pg_relation_size(C.oid) DESC
  LIMIT 20;

产生:

              关系| 尺寸  
------------------------------------ + ---------  
  pg_toast.pg_toast_16874 | 89 GB  
  littles00.warmstates | 1095兆字节  
  ...  
(20列)

该TOAST表用于一个名为“时间序列”的表,该表保存了大数据记录。SUM(LENGTH(blob)/1024./1024.)时间序列中所有记录的A 对该列产生约16GB。应该有什么理由这个表的TOAST表应尽可能大,因为它是。

我执行了VACUUM FULL VERBOSE ANALYZE timeseries,并且真空运行完全完成,没有错误。

信息:正在清理“ pg_toast.pg_toast_16874”
信息:“ pg_toast_16874”:在10448587页中发现22483个可移动的行版本10475318不可移动的行
详细信息:无法删除0个死行版本。
不可移动的行版本范围从37到2036字节长。
有20121422个未使用的项目指针。
总可用空间(包括可移动行版本)为0字节。4944885页已为空,或将为空,在表末尾包括0。包含0个空闲字节的4944885页是潜在的移动目标。
CPU 75.31s / 29.59u秒已过去877.79秒。
信息:索引“ pg_toast_16874_index”现在在179931页中包含10475318行版本
详细信息:删除了23884索引行版本。
101623索引页已被删除,101623当前可重用。
CPU 1.35秒/2.46微秒过去了21.07秒。

重新索引释放了一些空间(〜1GB)的表。我无法聚集该表,因为磁盘上没有足够的空间用于该进程,并且我正等待完全重建该表,因为我想找出为什么它比我们拥有的等效数据库大得多。

在PostgreSQL Wiki上查询一个查询-“ Show Database Bloat”,这就是我得到的:

current_database | 模式名| 表名| tbloat | wastedbytes | iname | 伊布洛特| 浪费字节  
----------------- + ------------ + ------------------- ------------- + -------- + ------------- + ------------- -------------------- + -------- + --------------  
ptrdb04 | somes00 | 时间序列| 1.0 | 0 | idx_timeseries_synchlevel | 0.0 | 0  
ptrdb04 | somes00 | 时间序列| 1.0 | 0 | idx_timeseries_localavail | 0.0 | 0  
ptrdb04 | somes00 | 时间序列| 1.0 | 0 | idx_timeseries_expirytime | 0.0 | 0  
ptrdb04 | somes00 | 时间序列| 1.0 | 0 | idx_timeseries_expiry_null | 0.0 | 0  
ptrdb04 | somes00 | 时间序列| 1.0 | 0 | uniq_localintid | 0.0 | 0  
ptrdb04 | somes00 | 时间序列| 1.0 | 0 | pk_timeseries | 0.1 | 0  
ptrdb04 | somes00 | idx_timeseries_expiry_null | 0.6 | 0 | ?| 0.0 | 0

看来数据库根本不认为该空间是“空”的,但是我只是看不到所有磁盘空间的来源!

我怀疑该数据库服务器决定使用4-5倍的磁盘空间来保存从其他数据服务器提取的相同记录。我的问题是:有没有办法验证行的物理磁盘大小?我想将此数据库上的一行的大小与另一个“健康”的数据库进行比较。

感谢您的任何帮助,您可以提供!

更新1

由于其大小,我最终从转储的架构中重建了表(无法再将其放在另一天)。通过软件同步过程同步数据后,TOAST表约为〜35GB;但是,我只能从该blob列中获得约9GB的存储空间,该存储区应该是最长的值。不确定其他26GB的来源。聚集,真空已满,重新索引无济于事。该postgresql.conf中的本地和远程数据服务器之间的文件正好相同。此数据库是否有任何原因试图在磁盘上存储较大空间的每个记录?

更新2-固定

我最终决定完全从头开始完全重建数据库,甚至可以在系统上重新安装PostgreSQL84软件包。数据库路径被重新初始化,表空间被清除干净。第三方软件同步过程重新填充了表,最终大小为〜12GB!不幸的是,这绝不能帮助解决问题的确切出处。我将看一两天,看看振兴的数据库在处理TOAST表的方式上是否存在任何重大差异,并将这些结果发布在此处。

关系大小


ptrdb04=> SELECT nspname || '.' || relname AS "relation",
ptrdb04->     pg_size_pretty(pg_relation_size(C.oid)) AS "size"
ptrdb04->   FROM pg_class C
ptrdb04->   LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
ptrdb04->   WHERE nspname NOT IN ('pg_catalog', 'information_schema')
ptrdb04->   ORDER BY pg_relation_size(C.oid) DESC
ptrdb04->   LIMIT 2;

        关系          |   大小   
 ------------------------- + --------- 
 pg_toast pg_toast_17269 | 18 GB 
 somes00 温暖状态        | 1224 MB
 2   

VACUUM VERBOSE ANALYZE timeseries;

INFO:“时间序列”:在58382个页面中的58130个中找到12699个可移动,681961不可移动的行版本
详细信息:无法删除0个死行版本。
有105847个未使用的项目指针。
0页完全为空。
CPU 0.83s / 2.08u秒过去了33.36秒。
INFO:清理“ pg_toast.pg_toast_17269”
INFO:扫描索引“ pg_toast_17269_index”以删除2055849行版本
详细信息:CPU 0.37秒/2.92微秒过去了13.29秒。
INFO:“ pg_toast_17269”:在518543页中删除了2055849行版本
详细信息:CPU 8.60秒/3.21微秒过去了358.42秒。
INFO:索引“ pg_toast_17269_index”现在在36786页中包含7346902行版本
详细信息:2055849索引行版本已删除。
10410个索引页已被删除,5124当前可重用。
CPU 0.00s / 0.00u秒经过了0.01秒。
信息:“ pg_toast_17269”:在2378779页中的1257871中找到1286128可移动,2993389不可移动行版本
详细信息:无法删除0个死行版本。
有18847个未使用的项目指针。
0页完全为空。
CPU 26.56s / 13.04u秒过去了714.97秒。
INFO:分析“ fews00.timeseries”
INFO:“时间序列”:扫描了680000页中的30000页,其中包含360192个活动行和0个无效行;样本30000行,估计总行821022

重建后唯一显着的差异(磁盘使用率除外)是

INFO:“ pg_toast_17269”:找到1286128可移动的,2993389不可移动的行版本
正如@CraigRinger在评论中提到的。不可移动的行数是多少比以前小。

新问题: 其他表会影响另一个表的大小吗?(通过外键等)重建表没有任何作用,但是重建整个数据库证明可以解决该问题。


您为什么不直接升级到9.2?与8.4相比,它在真空区域的改进更大(无论如何,明年8.4都将停产)
a_horse_with_no_name

我更新了帖子。升级不是由我们的商店完成的,不一定是我们的要求。不幸的是,我们没有升级到9+的选项。
BrM13 2013年

好。我只是想确保您没有忽略明显的;)
a_horse_with_no_name13年

Answers:


9

这个:

INFO: "pg_toast_16874": found 22483 removable, 10475318 nonremovable row versions in 10448587 pages 22483 removable, 10475318 nonremovable row versions in 10448587 pages

这表明潜在的问题是,某些东西仍然可以“看到”这些行,因此无法将其删除。

候选人是:

  • 准备好的交易丢失。检查pg_catalog.pg_prepared_xacts; 它应该是空的。也跑SHOW max_prepared_transactions; 它应该报告零。

  • 具有打开的空闲事务的长时间运行的会话。在PostgreSQL 8.4及更高版本中,这仅是SERIALIZABLE事务问题。检查pg_catalog.pg_stat_activity<IDLE> in transaction会议。

您的客户端很可能在长时间的空闲时间内无法提交或回滚事务。

如果事实并非如此,那么我接下来要检查的是对octet_size感兴趣的表的每一列进行求和。将其pg_relation_size与桌子及其TOAST边桌的进行比较。如果差异很大,则不再可见的行可能会占用空间,并且您可能确实存在表膨胀问题。如果它们非常相似,则可以通过汇总每列的八位位组大小,获取最高的“ n”值等来开始缩小空间使用范围。


1)pg_prepared_xacts和max_prepared_transactions确实返回为空。2)肯定有一些IDLE事务SELECT * FROM pg_stat_activity WHERE current_query LIKE '<IDLE>%';可以带回大约30-40个结果;但是,这似乎很正常。我检查了一些“健康”服务器,它们是相同的。
BrM13 2013年

3)这是我所做的。在时间序列列中循环,拉出octet_length(column)。将每个值乘以行计数并求和。对于时间序列,我获得了约430MB(与pg_relation_size的493MB接近)和438MB的TOAST表(使用chunk_id,chunk_seq,chunk_data列)。估计看起来是正确的,并且TOAST表与Relation_size的距离大约为2个数量级(今天为60GB)。好像我有肿胀,但没有传统肿胀(未使用的肿胀)。否则,FULLVAC应该解决该问题。
BrM13

@Brad Idle 会话很好,这只是一个有未解决事务的空闲会话,例如<IDLE> in transaction,并且只有在它们(a)空闲了一段时间并且(b)使用SERIALIZABLE隔离或者您使用8.3或比较老
Craig Ringer

@Brad有趣的是,TOAST虽然只有表格显得肿。顺便说一句,如果你已经使用VACUUM FULL了很多9.0之前的服务器上你要REINDEXVACUUM FULL这些版本可能会导致显著指数膨胀。我现在想知道是否有人FILLFACTOR在烤面包桌上放了一个荒唐的东西,尽管那不应该让您超过10倍的空间消耗。
Craig Ringer

感谢您对IDLE的说明。我想这就是您的意思,但是肯定知道是一件好事。至于FILLFACTOR,该表使用默认值。仅供参考-根据8.4创建表文档,默认值为100,并且您无法为TOAST表设置FILLFACTOR。
BrM13

0

我对为什么它肿没有任何见解。但是我做了一些搜索,也许这个链接有一些见识:http : //postgresql.1045698.n5.nabble.com/A-154-GB-table-swelled-to-527-GB-on-the-Slony-slave -how-to-compact-it-td5543034.html ...这不是您的确切情况,但也许已经足够接近,可以帮助您深入探究

但是,我认为此时压缩该表的唯一方法是将其聚类。由于您的磁盘空间不足,因此这是一个问题。

这是我的建议:在具有大量额外空间的其他驱动器上创建表空间,然后将问题表分配给该表空间。PostgreSQL会将表复制到新的表空间中(可能是在过程中对其进行表锁定,因此您需要一个维护窗口)。然后对表进行VACFULL(清除表在默认表空间中占用的大部分旧空间)。然后对表进行聚类,它应该自行压缩。然后将其放回默认表空间并再次运行VACFULL(以清除新表空间中未使用的空间)。


我实际上最终重建了表(转储架构并从中进行重建),并直接从一个远程数据库中提取了数据。完成此过程后,数据库仍为35GB,其中只有9GB属于“宽” blob列。群集,真空已满,重新索引,我仍然坐在大量神秘的磁盘使用情况上。
BrM13

链接已死:(
hayd
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.