PostgreSQL 清理过程

  • Post author:
  • Post category:其他


VACUUM的两个主要任务是删除死亡元组和冻结事务ID。

为了删除死亡元组,VACUUM提供了两种模式,即Concurrent Vacuum和Full Vacuum。

Concurrent Vacuum通常简称为VACUUM。它在删除表文件中的死亡元组时,其他事务仍可以在此进程运行时读取表。而Full VACUUM在运行时其他事务不能访问表。



概述

VACUUM对数据库中的表执行以下的任务:

1、删除死亡元组

删除死亡元组和整理每个页面的活元组。

删除指向死元组的索引元组。

2、冻结old txids

如有必要,冻结元组的old txids。

更新冻结的txid相关的系统目录(pg_database和pg_class)。

如果可能,清除clog不必要的部分。

3、其他

更新已处理表的FSM和VM。

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



VACUUM处理步骤

(1)从指定的表中获取每个表。

(2)获取表的ShareUpdateExclusiveLock锁。这个锁允许读取其他事务。

(3)扫描所有页面得到所有死元组,如果有必要冻结旧元组。

(4)删除指向各自死亡元组的索引元组(如果存在的话)。

(5)对表格的每一页,执行以下步骤(6)和(7)。

(6)移除死去的元组,在页面中重新分配活着的元组。

(7)更新目标表中的FSM和VM。

(8)使用index_vacuum_cleanup()@indexam.c函数清理索引。

(9)截断最后一页,如果最后一页没有任何元组。

(10)更新目标表中与vacuum处理相关的统计信息和系统目录。

(11)更新与真空处理相关的统计数据和系统目录。

(12)如果可能,删除clog中不必要的文件和页面。



VM(可见性映射)

VACUUM处理成本很高;因此,在8.4版本中引入VM以减少此成本。

VM的基本概念很简单: 每个表都有一个单独的可见性映射,它保存表文件中每个页面的可见性。页面的可见性决定了每个页面是否有死元组。真空处理可以跳过没有死元组的页面。

假设该表由三个页面组成,第0页和第2页包含死元组,第1页不包含。该表的VM保存有关哪些页包含死元组的信息。此时,vacuum处理跳过第1页,直接参考VM的信息进行处理。



Freeze处理

冻结处理有两种模式,根据特定条件在任意一种模式下执行。为了方便起见,这些模式被称为Lazy(惰性)模式和eager(急切)模式。

注:concurrent Vacuum通常被称为“lazy Vacuum”。然而,本文档中定义的lazy模式是冻结处理执行的一种模式。

冻结处理通常在lazy模式下运行;但是,在满足特定条件时运行eager模式。

在lazy模式下,冻结处理只扫描使用目标表的VM各自包含死元组的页面。

相反, eager模式扫描所有页面,而不管每个页面是否包含死元组,它还更新与冻结处理相关的系统目录,并在可能的情况下删除clog中的不必要部分。



Autovacuum

VACUUM已经通过autovacuum守护进程实现了自动化;因此,PostgreSQL的操作变得非常简单。

autovacuum守护进程定期调用几个autovacuum_worker进程。默认情况下,它每1分钟唤醒一次(由autovacuum_naptime定义),并调用三个worker(由autovacuum_max_works定义)。

由autovacuum调用的autovacuum工作器对各个表并行地逐步执行VACUUM处理,而对数据库活动的影响最小。



Full VACUUM

虽然并行VACUUM对操作是必要的,但它是不够的。例如,即使删除了许多无用的元组,它也不能减少表的大小。

死去的元组被移除;然而,表的大小并没有减少。这不仅浪费磁盘空间,而且对数据库性能有负面影响。

为了处理这种情况,PostgreSQL提供了FULL VACUUM模式。

(1)创建新表文件;

(2)复制活元组到新表;

(3)删除旧文件,重建索引,更新statistics, FSM, VM;

使用VACUUM FULL命令时应该考虑两点。

  1. 当执行FULL VACUUM处理时,没有人可以访问(读/写)表(阻塞读写)。
  2. 临时使用的磁盘空间最多为表的两倍;因此,在处理大表时,有必要检查剩余磁盘容量。



版权声明:本文为yunmu666原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。