Postgres数据库vacuum介绍
金蝶云社区-刘映希
刘映希
0人赞赏了该文章 113次浏览 未经作者许可,禁止转载编辑于2023年08月21日 10:26:03

  vacuum概述

众所周知,vacuum是PostgreSQL中的一个辅助进程,它主要负责完成两个主要任务:删除死元组(Dead Tuples)和冻结事务ID(Freezing Tansaction Ids)。

早期的版本中,vacuum必须要手动触发,而在8.0后,其已经通过守护进程(autovacuum)实现自动化。其好处是它定期运行ANALYZE进程来收集频繁更新表的最新统计信息,这使查询规划器能够优化它的计划。

每当postmaster服务启动之后,系统就会fork()一个autovacuum守护进程, 该守护进程将会周期性地检查指定表(若未指定具体表,则检查系统所有表)中的各块是否存在死元组等相关逻辑处理。和另外几个辅助进程一样,VACUUM进程的运行状态也会受到postmaster服务的监视。postmaster服务会定期去检测VACUUM进程的运行情况,一旦发现该进程不存在,则会立刻重新fork()一个autovacuum辅助进程。

vacuum主要工作过程

数据库中autovacuum由autovacuum launcher进程定期的拉起autovacuum worker线程来进行工作,autovacuum launcher 是守护进程,autovacuum worker 是实际进行工作的进程。

      第一部分

l  从指定的表中依次处理每一张表,

l  获取表上的ShareUpdateExclusiveLock锁(该锁允许其他事物对该表进行读取)。

l  扫描表中的所有页面,获取所有的死亡元组,(死元组的列表存储在本地内存的maintenance_work_mem里)

l  如果有必要,冻结旧的元组的事务标识

l  移除指向死亡元组的索引元组

      第二部分

l  移除每一页中的死亡元组,并对每一页内的的活元组进行碎片整理,重排本页的活元组

l  更新已经处理的空闲空间映射(FSM)和可见性映射(VM)

l  PG会不断执行这个过程直至最后一页

      第三部分

l  如果最后一个页面没有任何元组,则截断最后一页

l  更新与冻结事务标识相关的系统视图(pg_class与pg_database)

l  释放ShareUpdateExclusiveLock锁

      第四部分

l  更新一些统计信息(pg_stat_all_tables等)

l  移除不必要的提交日志文件,移除CLOG(10版本及以后为xact)中的非必要文件与页面

    (当更新pg_database.datfrozenxid时,会尝试删除不必要的CLOG)

 

vacuum相关概念-VM

vacuum过程是一种维护过程,它的两个主要任务是删除死元组,以及冻结事物标识,由于清理过程涉及全表扫描,因此该过程代价高昂,在PG8.4版本中引入了可见性映射(VM)文件来提高移除死元组的效率,在PG9.6版本中增强了VM,从而改善了冻结的过程。

vacuum相关概念-冻结

冻结的过程有两种模式,依特定条件而择其一执行。一种为惰性模式另一种为迫切模式。惰性模式下,冻结过程仅适用目标表对应的VM扫描包含死元组的页面。迫切模式会扫描所有的页面,无论其是否包含死元组,都会更新与冻结过程相关的系统视图,并在可能的情况下删除不必要的CLOG文件。

vacuum相关概念-死元祖

当元组被修改时,元组会复制出多个版本(MVCC),当事物提交后,历史的版本对其它事物不可见,被标记为死元祖,等待autovacuum清理。死元组的产生也是因为PostgreSQL中没有单独的回滚段,而是将历史版本直接记录在数据页面中。

Vacuum 优化浅析

1、什么时候会触发autovacuum?

Ø  表上(update,delete 记录) >= autovacuum_vacuum_scale_factor* reltuples(表上记录数) + autovacuum_vacuum_threshold如果表有10000行,则表中的行如果更新或删除的数量超过50+10000*0.2=2050行,autovacuum就开始工作,而100万行数据需要修改50+1000000*0.2=200050行才会触发autovacuum所以随着一个表的数据量增多,触发aotovacuum会越来越少,最终导致表的膨胀越来越大

Ø  表上事务的最大年龄配置参数autovacuum_freeze_max_age,默认为2亿,达到这个阀值将触发 autovacuum进程,从而避免 wraparound。

      2、优化方案

Ø  增加autovacuum_work_mem可以加快清理速度

Ø  在postgresql.conf中忽略比例因子,设置较大的阈值(例如设置autovacuum_vacuum_scale_factor = 0和autovacuum_vacuum_threshold = 10000),然后根据各个表的delete和update频繁程度以及表的数据量单独为每个表设置阈值:ALTER TABLE test SET (autovacuum_vacuum_threshold = 100);

Ø  vacuum并不能在一张表上做并发整理,所以表不能太大。有一些用户的一张表到达了好几十GB甚至上百GB,对于这些大表,vacuum整理耗时过长,利用pg_pathman插件改造成分区表是个比较好的选择。

Ø  随着磁盘IO性能的增强,早期的默认参数设置并不能满足数据库的最大性能要求,因此适时调整是必要的。如vacuum_cost_limit默认值为200,通常太小了,对于有cache的raid卡,这个值应该设置成1000左右,对于ssd,应该设置成10000。很多一些用户就是因为这个参数设置的太小,导致一些用户旧版本数据没有得到及时清理,导致数据库的年龄不断增加最终导致宕机。又如autovacuum_vacuum_cost_delay,默认20ms,可以根据实际情况适当缩短。

注意事项

VACUUM和VACUUM FULL两者的主要区别有如下几点:

(1) VACUUM执行时,不会锁住表;而VACUUM FULL执行期间则会锁住目标表,其他事务无法进行读/写,不允许并行操作。

(2) VACUUM只是将目标表中的死元组的空间转换为可使用状态;而VACUUM FULL则会删除目标表,并释放死元组占用的磁盘空间,将其归还给操作系统。理想情况下,PostgreSQL的应用程序设计方案避免使用VACUUM FULL方式。首先它使用互斥锁,会阻止其他一切尝试操作该目标表的读写行为;其次,由于它本质是上创建一个新的(堆)表文件,然后将所有活元组(live tuples)导入到新表文件中,所以其执行速度比较慢,效率低。当然,优点是执行VACUUM FULL后其表文件只存在活元组,由于没有多余的死元组,因此,将大大提高查询执行的效率。总而言之,若可以,则尽量不去使用VACUUM FULL,除非你十分清楚目标表中大部分的元组都是死元组。

autovacuum主要参数介绍如下:

image.png


本文转载自:公共号金蝶云·天梯

作者:孙凡

原文链接:公共号金蝶云·天梯

赞 0