从tuple格式看PG设计之VACUUM
PG行记录格式
t_xmin 插入记录/元组 事务txid t_xmax 删除/修改记录/元组 事务txid, 新插入t_xmax设置为0, t_cid 事务内SQL执行顺序号,0开始 t_ctid 指向元组/新元组(block,offset) t_ctid t_infomask2 HEAP_HOT_UPDATED(旧元组)HEAP_ONLY_TUPLE(无索引新元组)标志位 t_infomask 事务标准位,提交,撤销,进行中,子事务进行中 t_hoff 用户数据的偏移量 NULL bitmap null值位图 User data 实际的数据
复制
PG更新记录不同于其他数据库的inplace,not inplace,not inplace, not inplace
已修改或已删除的记录也存在heap,这就带来了2个问题:表膨胀与垃圾清理IO负担;这也造成了其他数据库最多提一下降低高水位问题,而PG强调表膨胀与高水位。
另外值得吐槽的是由于tuple存储的t_xmin,t_xmax只有32位,较其他数据库而言,再遭遇一个迫切的问题就是,事务号耗尽,当然循环使用规避一些问题,但又带来了事务ID回卷问题,进而出现只有PG才会出现的ID回卷与冻结。比较事务发生早或迟,到底是过去还是未来都不能单纯比较txid大小,而需要比较跨度有没有达到2^31即diff = (int32) (id1 - id2);
应运而生的vacuum至此也有2个主要的任务:移除dead tuple与freeze。按照是否扫描所有页面,是否降低高水位.
lazy mode
eager mode
vacuum full
开启autovacuum触发
vacuum_freeze_min_age 触发lazy mode
vacuum_freeze_table_age 触发 eager mode
关闭autovacuum强制触发
autovacuum_freeze_max_age
各模式缺点
lazy mode 根据visibility map跳过扫描,page没有死元组但有旧事物未被freeze
加锁:SharedUpdateExclusiveLock ,允许其他事物对该表进行读取,可并发rw
通常在延迟模式下运行;
eager mode 根据visibility map, all_frozen来跳过
vacuum full 类
类似重组表,加ACCESS EXCLUSIVE(MDL Writer)阻塞访问
衍生IO问题
a.freeze 风暴
版本过低致使集中vacuum freeze prevent wrap,v9.6后改进
大表的最老的事务号可能都是相差不大,设置不同的freeze,规避集中爆发
alter table t set (autovacuum_freeze_max_age=xxxx);
业务空闲期定时任务vacuum freeze
b.表膨胀
pg_freespacemap 监控,pg_repack在线reorg
c.HOT降低索引维护
page预留空间,发挥HOT优点
alter table table_xx set (fillfactor=80);
d.规避vacuum过晚触发
小表延后vacuum,大表提前触发,减少vacuum堆积工作量
alter table table_xx set (autovacuum_vacuum_scale_factor =0.001);
alter table table_xx set (autovacuum_vacuum_threshold=10000);
总结:可以看到VACUUM也是构建了一道道防线,针对开启自动清理,未开启自动清理强制触发,以及MVCC排他锁阻塞访问的重组表,释放freespace,降低HIGH WATER MARK