一、Vacuum概述
1、简述
通过学习十五章可知,PG块中被删除的行,只是逻辑上删除(标记为删除状态),物理上还保留在块中,如果长时间不清理,会造成垃圾空间膨胀。
设想,如果一个块中有50%死元组,那么就浪费50%的存储空间;如果读到内存,也会浪费50%的内存空间,所以需要定期的清理,定时清理工作由 Autovacuum来操作,也可以手动Vacuum操作。
pg_freespacemap插件可以很好的监测块中空间的使用情况,可当作full vacuum操作的参考信息,可以提前安装。
2、Vacuum的作用
Vacuum是PG自带的空间管理工具,用于处理对数据库中的指定表或所有表执行以下任务:
(1)空间管理:移除死元组
删除死元组,并对每个页面的活元组进行碎片整理;
删除指向死元组的索引元组;
(2)冻结:冷冻老的Txid
必要时冻结老元组的Txid;
更新冻结的与系统目录( pg_database和pg_class)相关的txid;
如有可能,移除clog中不必要的部分;
(3)统计:更新统计数据
pg_stat_all_tables等;
(4)其他
更新已处理表的FSM和VM文件;
3、VACUUM处理流程
扫描
(1)从指定的表中获取每个表。
(2)获取表的 ShareUpdateExclusveLock锁。此锁允许读取其他事务。
(3)扫描所有页面以获取所有死元组,必要时冻结旧元组。(关于冻结操作,可详见十八章)
(4)如果存在,则移除指向相应死元组的索引元组。
(5)对表的每一页执行以下步骤(6)和(7)
执行
(6)移除死元组并重新分配页面中的活元组。
(7)更新目标表的相应FSM和VM。
更新
(8)如果最后一页没有元组,则截断最后一页。
(9)更新与目标表的真空处理相关的统计信息和系统目录。
(10)更新与真空处理相关的统计数据和系统目录。
(11)如果可能的话,删除不必要的文件和clog的页面,如图:
二、可见性地图(_vm)的作用
可见性地图中记录了 含有被删除行的数据块id,为Vacuum操作提供参考。可以提高Vacuum操作的效率。
三、Full Vacuum
1、原理说明
普通Vacuum后,有效数据所在块的位置不会变化,即使所在块的空闲空间很大。此时,如果存在全表扫描,对于存放在3个块中的3条数据,需要进行3次I/O操作,如图:
而进行Full Vacuum操作后,会将有效数据尽可能地重新存放在同一个块中,此时全表扫描的I/O次数将大大降低,提升数据库的性能;
因为此过程中创建了新的数据块,所以会导致relfilenode发生变化,即与oid不再一致。
2、做个实验
#创建一个测试表
CREATE TABLE acc(aid int,info text,c_time timestamp);
INSERT INTO acc select generate_series(1,100000),md5(random()::text),clock_timestamp();
#查询测试表的页存储情况
SELECT count(*) as "number of pages",
pg_size_pretty(cast(avg(avail) as bignit)) as "Av.freespace size",
round(100*avg(avail)/8192,2) as "Av.freespace ratio"
FROM pg_freespace('acc');
#模拟业务
DELETE FROM acc WHERE aid %10!=0 OR aid <100;
#手动执行空间回收,并查询回收后的页存储情况
VACUUM acc;
SELECT count(*) as "number of pages",
pg_size_pretty(cast(avg(avail) as bignit)) as "Av.freespace size",
round(100*avg(avail)/8192,2) as "Av.freespace ratio"
FROM pg_freespace('acc');
#手动执行Full Vacuum操作,并查询页存储情况
VACUUM FULL acc;
SELECT count(*) as "number of pages",
pg_size_pretty(cast(avg(avail) as bignit)) as "Av.freespace size",
round(100*avg(avail)/8192,2) as "Av.freespace ratio"
FROM pg_freespace('acc');