1.概述
随着数据库的运行,存储空间里会产生一些无用的数据,需要进行清理。
产生这些无用数据的原因有:
? 行被删除
? 插入行的事务终止
? 由更新产生的旧的行版本
需要回收的存储空间主要包括以下几个方面:
? 行版本(占用空间最大)
? 行版本指针(占用空间最小)
? 索引项
2.回收方法
2.1 表的单页清理
通过SELECT,UPDATE和DELETE访问表时,会触发表的单页清理。清理对象仅限于被废弃的行版本(对任何事务都不可见)。同时标记行版本指针为Dead状态。下次执行vacuum时,会回收不用的索引项和行版本指针。
删除前:
删除后:
*)行版本指针共有4个状态,存储在lp_flags域:
Unused
Normal
Redirect
Dead
2.2 vacuum
通过vacuum或autovacuum清理时,被废弃的行版本,行版本指针和索引项都会得到清理。普通的vacuum不会释放存储空间给OS,除非在表文件的末尾有连续的空页。vacuum full会将整个数据重写一遍,仅保留有用的数据。vacuum full时要锁住整个表,会影响其它并发作业。
vacuum后:
3.更新的优化
满足以下条件时,采用称之为HOT(heap-only tuples)更新的技术提高性能。
1)新旧行版本存储在同一个页上
2)更新不涉及被索引列值的变更
通过行版本头部的ctid或者行版本指针的lp_flags(Redirect)+lp_off让旧版本指向新版本,形成一个HOT更新链。这样在更新时就可以重用原来的索引项,避免删除和追加索引项。索引项仍然指向旧的行版本指针,然后通过HOT更新链找到对应的新版本。
使用ctid或lp_flags(Redirect)+lp_off形成HOT更新链的区别在于:前者保留了旧的行版本,而后者用于旧的行版本已被回收的情况。当旧的行版本对某些活动事务仍然可见时,是不能被回收的。HOT更新时对于处于HOT更新链中间位置的行版本指针是可以被立即回收的(头指针被索引使用,尾指针指向最新的行版本,所以要保留)。
初始状态:只有一个版本
第一次更新:通过旧行版本头部的ctid指向新行班本
第二次更新:V1的行版本空间被再利用。并且通过Redirect将索引使用的第一个行版本指针引向保留下来的最老的行版本。
第三次更新:
最终由于其他操作触发废弃的行版本被回收:
4.性能提示
为了能让HOT更新充分发挥作用,需要尽量减少不必要的索引,并合理设置表的存储参数fillfactor。
fillfactor控制插入时页存储空间的使用率,取值范围为10%~100%,缺省值为100,即不为HOT更新保留空间。
对于频繁更新非索引列的表,应该将fillfactor适当设小。
5.参考
阅读(740) | 评论(0) | 转发(0) |