暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PolarDB for PostgreSQL 开源必读手册-VACUUM处理

Aug_33 2023-11-20
278


image.png

 

vacuum的工作内容为空间清理,最主要的工作内容为将数据块中被删除的行的空间进行释放。

 

比如当前的数据块存在两行数据,用户对最下面一行数据做了修改,PolarDB的操作方式不是在当该行进行修改,而是将该行标识为删除,然后在数据块里重新插入修改后的新行。被标识为删除的行不会立刻释放空间,而是需要由vacuum来做释放操作。

 

另外,vacuum还负责冷冻老的Txid以及收集表的统计信息,为优化器提供可用信息做参考,并且更新表的文件。

 

image.png

vacuum的操作过程分为三部分。

 

第一部分,准备创建死元组列表。需要从各个数据库里搜索哪些表达到了整理的条件,然后将这些表组成列表。

 

第二部分,清理阶段。将列表里包含有被删除的行的空间进行释,同时更新FSM和VM两个文件。

 

第三部分,善后工作。如果最后一页没有元组,则将其删除,以减少数据文件的尺寸。如果需要,同时会将不必要的Clog删除。

 

image.png

 

比如上图中第一个数据块内有三行,其中有一行已被删除,PolarDB将其标识为dead tuple。做完vacuum以后,Tuple_2的空间被释放,剩余两行被整理后更加紧凑。同时,被删除行的指针没有删除,插入新行后,该指针会指向新行,减少了维护操作,提高了效率。

 

image.png

 

做vacuum时,正常情况下需要将表的所有数据扫描一遍。为了提高效率,PolarDB使用了VM(可见性地图)数据文件。

 

如上图,比如当前有三个数据块,第二块里不包含被删除的行,则VM会将其标识为1。后续做vacuum时,会跳过VM=1的页,提高vacuum的效率。

 

9.6版本以后,可见性地图除了提高 vacuum的效率以外,同时也提高了冻结的效率。

 

image.png

 

数据库为了描述事务操作的先后顺序,会为事务分配ID号,即TxID。

 

TxID不会无限增大,而是循环使用。最大的可用事务ID为42亿,PolarDB将其分为两半,前21亿代表“过去的或当前正在用的”,此类事务ID修改的行为对用户可见;而后21亿事务ID代表“未来的”,修改的函数不可见。

 

两个部分的21亿事务ID可以循环使用。比如前面的21亿使用完以后,再用后面的21亿,使用完以后再重新使用前面的21亿。

 

image.png

 

冻结主要针对可见性规则。

 

比如当前正在使用后21亿的TxID,而前21亿中某个数据块里仍有数据,需要对用户可见。因此,将其标记为冻结,使得其可见。

 

冻结处理分为懒惰模式和急切模式。懒惰模式指每次小部分、分批次地进行冻结,类似于日常做卫生;急切模式指大批量地冻结,类似于年终大扫除。

 

image.png

 

惰性冻结的公式中,OldestXmin指当前最小的事务id,vacuum_freeze_min_age是一个固定参数,默认为5000万。

 

image.png

 

以上图为例,假设当前的最小事务id为50002500,意味着要将小于或等于2500的ID都冻结。

 

冻结时,首先会先判断VM值,如果VM为1(当前数据块内不存在被删除的行),则跳过,不对其进行冻结。然后判断每一个块内每一行的事务id,如果id<=2500,则在其某一位上标记为frozen;若id>2500,则跳过。比如上图中Turple9内最后一行id为3000,因此不冻结。

 

image.png

 

急性冻结的触发条件为:自上一次急性冻结后,TxID使用了1亿5000万后会再次触发。

 

image.png

 

如上图,如果从未做过急性冻结,则datfrozenxid默认为560。发生急性冻结后,datfrozenxid会变为该次急性冻结的TxID。

 

image.png

 

如上图所示,当前最小的事务id为150002000,150002000-5000000=100002000,因此事务id小于100002000的行全部进行冻结。

 

比如当前有三个块,PolarDB会对三个块全部进行扫描,事务ID小于100002000的,在该行某一位做frozen标记。

 

可以理解为,只有很早以前的事务修改的行会被冻结,最新修改的行不冻结。



 

image.png 

 

做完冻结后,所有数据库的列均会写上被冻结时的ID,等下一次发生急性冻结时,ID会被更新。

 

image.png

 

 

 

查询结果如上图,比如id=651意味着该表没有被冻结,此id为事务创建时的id。而id=0意味着数据库是初始化时创建的。

 

image.png

 

为了提高急性冻结的效率,PolarDB在VM上又做了改进。

 

上次冻结后(包括惰性冻结与急性冻结)至今没有发生变化的,状态为1;上次惰性冻结没有发生的,状态为0;冻结后发生变化的,状态为0。

 

做急性冻结时,状态为1则跳过,状态为0则进行急性冻结,以减少冻结工作量。

 

image.png

 

PolarDB9.6以后,提供了专门的后台进程做autovacuum。默认每10分钟执行一次,由autovacuum参数定义间隔时间。

 

每次做vacuum时,默认用三个worker进程,每个进程同一时间只能负责一个数据库里的表。如果想增加autovacuum的进程数,可以通过autovacuum_max_workers参数进行修改。

 

image.png

 

vacuum分为普通vacuum和Full Vacuum。

 

上图为普通vacuum操作。比如当前有三个块,紫色标示都是被删除的行。做了普通vacuum以后,三个块均保留,但里面只有少量数据。

 

image.png

 

为了减少数据文件的尺寸,可以做Full Vacuum。将块中被删除的行的空间清理后,会再新建一个数据文件,为其分配一个块。然后将剩下的行放入新的数据文件的块中,将原来的数据文件删除。

 

如果检测到数据块很多,且每个块内的可用空间也很多时,建议做Full Vacuum。

 

image.png

 

比如上图,表中一共有1640个数据块,每个数据块内的可用空间为99个字节。

 

image.png

 

对该表做delete操作并进行普通vacuum后,每个块的可用空间为7124字节,空闲率达86.97%。

 

image.png

 

而对该表做Full Vacuum后,表内只剩164个数据块,且每个块内的可用空间为0,数据文件的尺寸大幅降低。

 

image.png

 

如上图所示,表内原先有94个块,做完普通vacuum后依然为94个块,但是做了Full Vacuum后,只剩10个块。

 

将来做全表扫描时,扫描量从94个块降低至10个块,扫描效率得到了极大提升。

最后修改时间:2023-11-20 13:31:19
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论