PostgreSQL vacuum原理一功能与参数

从上篇“PostgreSQL MVCC 源码实现 【】”中,我们知道,PG并没有像Oracle那样的undo来存放旧版本;而是将旧版本直接存放于relation文件中。那么带来的问题就是dead tuple过多,导致relation文件不断增大而带来空间膨胀问题。为了解决这个问题,PG中引入了vacuum后台进程,专门来清理这些dead tuple,并回缩空间。当然vacuum的作用不仅在此,它还有以下其它功能:

一、vacuum的功能

1.回收空间

这个通常是大家最容易想起来的功能。回收空间,将dead tuple清理掉。但是已经分配的空间,一般不会释放掉。除非做vacuum full,但是需要exclusive lock。一般不太建议,因为如果表最终还是会涨到这个高水位上,经常做vacuum full意义不是非常大。一般合理设置vacuum参数,进行常规vacuum也就够了。

2.冻结tuple的xid

PG会在每条记录(tuple)的header中,存放xmin,xmax信息(增删改事务ID)。transactionID的最大值为2的32次,即无符整形来表示。当transactionID超过此最大值后,会循环使用。

这会带来一个问题:就是最新事务的transactionID会小于老事务的transactionID。如果这种情况发生后,PG就没有办法按transactionID来区分事务的先后,也没有办法实现MVCC了。因此PG用vacuum后台进程,按一定的周期和算法触发vacuum动作,将过老的tuple的header中的事务ID进行冻结。冻结事务ID,即将事务ID设置为“2”(“0”表示无效事务ID;“1”表示bootstrap,即初始化;“3”表示最小的事务ID)。PG认为被冻结的事务ID比任何事务都要老。这样就不会出现上面的这种情况了。

3.更新统计信息

vacuum analyze时,会更新统计信息,让PG的planner能够算出更准确的执行计划。autovacuum_analyze_threshold和autovacuum_analyze_scale_factor参数可以控制analyze的触发的频率。

4.更新visibility map

在PG中,有一个visibility map用来标记那些page中是没有dead tuple的。这有两个好处,一是当vacuum进行scan时,直接可以跳过这些page。二是进行index-only scan时,可以先检查下visibility map。这样减少fetch tuple时的可见性判断,从而减少IO操作,提高性能。另外visibility map相对整个relation,还是小很多,可以cache到内存中。

二、vacuum参数介绍

autovacuum有好多参数,用来控制其行为,大致有以下几个:
• autovacuum:默认为on,表示是否开起autovacuum。默认开起。特别的,当需要冻结xid时,尽管此值为off,PG也会进行vacuum。
• autovacuum_naptime:下一次vacuum的时间,默认1min。 这个naptime会被vacuum launcher分配到每个DB上。autovacuum_naptime/num of db。
• log_autovacuum_min_duration:记录autovacuum动作到日志文件,当vacuum动作超过此值时。 “-1”表示不记录。“0”表示每次都记录。
• autovacuum_max_workers:最大同时运行的worker数量,不包含launcher本身。
• autovacuum_vacuum_threshold:默认50。与autovacuum_vacuum_scale_factor配合使用, autovacuum_vacuum_scale_factor默认值为20%。当update,delete的tuples数量超过autovacuum_vacuum_scale_factor*table_size+autovacuum_vacuum_threshold时,进行vacuum。如果要使vacuum工作勤奋点,则将此值改小。
• autovacuum_analyze_threshold:默认50。与autovacuum_analyze_scale_factor配合使用, autovacuum_analyze_scale_factor默认10%。当update,insert,delete的tuples数量超过autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold时,进行analyze。
• autovacuum_freeze_max_age和autovacuum_multixact_freeze_max_age:前面一个200 million,后面一个400 million。离下一次进行xid冻结的最大事务数。
• autovacuum_vacuum_cost_delay:如果为-1,取vacuum_cost_delay值。
• autovacuum_vacuum_cost_limit:如果为-1,到vacuum_cost_limit的值,这个值是所有worker的累加值。

基于代价的vacuum参数:
• vacuum_cost_delay :计算每个毫秒级别所允许消耗的最大IO,vacuum_cost_limit/vacuum_cost_dely。 默认vacuum_cost_delay为20毫秒。
• vacuum_cost_page_hit :vacuum时,page在buffer中命中时,所花的代价。默认值为1。
• vacuum_cost_page_miss:vacuum时,page不在buffer中,需要从磁盘中读入时的代价默认为10。 vacuum_cost_page_dirty:当vacuum时,修改了clean的page。这说明需要额外的IO去刷脏块到磁盘。默认值为20。
• vacuum_cost_limit:当超过此值时,vacuum会sleep。默认值为200。

把上面每个cost值调整的小点,然后把limit值调的大些,可以延长每次vacuum的时间。这样做,如果在高负载的系统当中,可能IO会有所影响,因vacuum。但是对于表物理存储空间的增长会有所减缓。

在下一篇重点将在源码实现上。见

------------------------------------华丽丽的分割线------------------------------------

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/ebf6aa057e16a3cdc0084d2d5a3aac94.html