您的位置:首页 > 科技 > 能源 > 【PostgreSQL数据库表膨胀的一些原因】

【PostgreSQL数据库表膨胀的一些原因】

2024/11/18 11:48:59 来源:https://blog.csdn.net/weixin_47308871/article/details/142226815  浏览:    关键词:【PostgreSQL数据库表膨胀的一些原因】

PostgreSQL表膨胀的原因主要有两个:一个是垃圾数据,即dead tuple行数太多未及时清理,导致不能及时提供能重用的空间,二是数据页之间存在空闲空间。

1.表的填充因子设置

表的填充因子是个很神奇的东西,因为设置太大或者太小,都可能因不同原因引起表膨胀。

  • 较低的填充因子(例如 70%)意味着每个数据页中会留出 30% 的空闲空间。这样可以减少页面因更新而频繁分裂的可能性。这通常会导致表的实际磁盘使用量增加,因为每个页面上的有效数据量较少。所以造成表的膨胀。
  • 而表的 fillfactor 设置也可能会影响 VACUUM 的效果。如果 fillfactor 设置得过高,会导致表在插入新行时未能有效利用空间,增加了死元组的存在。(默认100)。

PostgreSQL 的表默认填充因子为 100,这意味着默认情况下,PostgreSQL 会尽量将每个页面填满数据,不留空间给未来的数据更新。假设一张表的填充因子设定为 70%。这样在 PostgreSQL 插入数据到页面时,会故意留下 30% 的空间空着,以便未来对现有数据行的更新。当表的填充因子更高(接近 100%)时,每个数据页面的空余空间更少,这可能导致数据行更新时空间不足,需要重新分配页面。

postgres=# alter table t1 set (fillfactor = 70);
ALTER TABLEpostgres=# SELECTrelname AS table_name,reloptions
FROMpg_class
WHERErelname = 't1';
+------------+-----------------+
| table_name |   reloptions    |
+------------+-----------------+
| t1         | {fillfactor=70} |
+------------+-----------------+
(1 row)

2. VACUUM和VACUUM FULL本身机制

VACUUM有时候只是标记了空间为可用,但磁盘空间可能不会立即反映出来。

3. AUTOVACUUM参数不合理死元组不能及时清理

调整 autovacuum 配置参数,特别是 autovacuum_vacuum_scale_factor 和 autovacuum_vacuum_threshold。例如,降低 autovacuum_vacuum_scale_factor 的值,可以让 autovacuum 更频繁地运行。

4.一些原因导致vacuum后没清理死元组

主要有如下几种方式

  1. 失效复制槽
  2. 长事务导致
  3. 存在未提交的prepare事务
  4. idle in transaction状态的事务
  5. 函数等内部结构涉及到表的访问
  6. hot_standby_feedback参数问题
  7. 索引状态问题
  8. 表和索引的并发访问

可以参考这篇文章:​https://blog.csdn.net/weixin_47308871/article/details/142226606?spm=1001.2014.3001.5502​

5.表的统计信息问题

如果表的统计信息有问题,可能会影响 VACUUM 的效果。

6.maintenance_work_mem参数设置太小死元组不能及时清理

maintenance_work_mem 设置得太低可能会限制 VACUUM 的效率,因为VACUUM过程需要在maintenance_work_mem里缓存dead tuple的tupleid,如果太小则可能分多次清理,每次在maintenance_work_mem缓存满之后就会触发一次清理,除非之外还可能涉及到多次扫描索引的问题。正常情况下,每满一次,就会重新扫描一遍所有的索引。

v11-v13引入的一个GUC参数vacuum_cleanup_index_scale_factor,但是在v14取消了,对于大量insert,没有update、delete操作的表的vacuum,或者常规静态表的vacuum会快很多,因为不需要scan index了。

而v12版本也在表级别增加了vacuum_index_cleanup参数,可以在创建表的时候设置,也可以alter table设置。参数可以控制VACUUM在是否禁用索引清理的情况下运行,默认值为true。v12版本的VACUUM引入了一个新的选项INDEX_CLEANUP,可以跳过索引的垃圾回收。

除此之外PostgreSQL-17版本之前,maintenance_work_mem虽然可以设置很大,但是对于vacuum本身的使用,有一个1GB的最大值限制,也就是不管你设置的多大,最多一个vacuum能用到的最多也就1GB。这个在PostgreSQL数据库的文档里也有相应的记录。从PostgreSQL-17版本取消了这个限制。

tupleid为6字节长度。1GiB可存储1.7亿条左右dead tuple的tupleid。默认垃圾记录约等于表大小的20%时触发垃圾回收, 8.9亿条记录的表20%的垃圾即1.7亿条dead tuple,因此超过8.9亿, 该表的垃圾回收就可能要多次扫描index了。所以以这个方向来看的话,PostgreSQL单表不建议超过8.9亿条记录。

7.磁盘性能问题导致死元组不能及时清理

磁盘 I/O 性能问题或数据文件系统的配置也可能影响 VACUUM 的效果,如果磁盘性能不好,可能VACUUM的效率比较低,死元组不能及时清理。可以使用fio、iostat 或 vmstat来检查磁盘IO情况。

8.PostgreSQL 的事务 ID (XID) Wraparound

PostgreSQL 使用事务 ID (XID) 来追踪事务。长时间运行的事务或频繁的事务生成可能导致 XID Wraparound 问题,这会影响 VACUUM 的效果。如果 XID 接近其最大值,数据库会进行 VACUUM 来防止 XID Wraparound,但这个过程可能不会完全清理死元组。

9.表的特定数据类型影响VACUUM

某些数据类型(例如数组类型或自定义数据类型)可能会影响 VACUUM 的行为,尤其是在处理复杂的数据结构时。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com