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等)。
(1)从指定的表中获取每个表。
(2)获取表的ShareUpdateExclusiveLock锁。这个锁允许读取其他事务。
(3)扫描所有页面得到所有死元组,如果有必要冻结旧元组。
(4)删除指向各自死亡元组的索引元组(如果存在的话)。
(5)对表格的每一页,执行以下步骤(6)和(7)。
(6)移除死去的元组,在页面中重新分配活着的元组。
(7)更新目标表中的FSM和VM。
(8)使用index_vacuum_cleanup()@indexam.c函数清理索引。
(9)截断最后一页,如果最后一页没有任何元组。
(10)更新目标表中与vacuum处理相关的统计信息和系统目录。
(11)更新与真空处理相关的统计数据和系统目录。
(12)如果可能,删除clog中不必要的文件和页面。
VACUUM处理成本很高;因此,在8.4版本中引入VM以减少此成本。
VM的基本概念很简单: 每个表都有一个单独的可见性映射,它保存表文件中每个页面的可见性。页面的可见性决定了每个页面是否有死元组。真空处理可以跳过没有死元组的页面。
假设该表由三个页面组成,第0页和第2页包含死元组,第1页不包含。该表的VM保存有关哪些页包含死元组的信息。此时,vacuum处理跳过第1页,直接参考VM的信息进行处理。
冻结处理有两种模式,根据特定条件在任意一种模式下执行。为了方便起见,这些模式被称为Lazy(惰性)模式和eager(急切)模式。
注:concurrent Vacuum通常被称为“lazy Vacuum”。然而,本文档中定义的lazy模式是冻结处理执行的一种模式。
冻结处理通常在lazy模式下运行;但是,在满足特定条件时运行eager模式。
在lazy模式下,冻结处理只扫描使用目标表的VM各自包含死元组的页面。
相反, eager模式扫描所有页面,而不管每个页面是否包含死元组,它还更新与冻结处理相关的系统目录,并在可能的情况下删除clog中的不必要部分。
VACUUM已经通过autovacuum守护进程实现了自动化;因此,PostgreSQL的操作变得非常简单。
autovacuum守护进程定期调用几个autovacuum_worker进程。默认情况下,它每1分钟唤醒一次(由autovacuum_naptime定义),并调用三个worker(由autovacuum_max_works定义)。
由autovacuum调用的autovacuum工作器对各个表并行地逐步执行VACUUM处理,而对数据库活动的影响最小。
虽然并行VACUUM对操作是必要的,但它是不够的。例如,即使删除了许多无用的元组,它也不能减少表的大小。
死去的元组被移除;然而,表的大小并没有减少。这不仅浪费磁盘空间,而且对数据库性能有负面影响。
为了处理这种情况,PostgreSQL提供了FULL VACUUM模式。
(1)创建新表文件;
(2)复制活元组到新表;
(3)删除旧文件,重建索引,更新statistics, FSM, VM;
使用VACUUM FULL命令时应该考虑两点。