0
点赞
收藏
分享

微信扫一扫

Postgres年龄冻结问题简介

niboac 2024-05-16 阅读 18

在之前的文章中(https://blog.51cto.com/u_16765851/10813155),我们提到了Postgres数据库的事务号是由32位无符号数据组成的,顺序产生,依次递增。有一个重要的概念,每个事务只能看见t_xmin比自己XID小且没有被删除的元组。由于事务号的大小是有上限的,所以在无特殊操作的前提下,当PostgreSQL的XID 到达40亿,就会造成溢出。

事务ID的比较方法:

实际上虽然txid空间有42亿,却并非按实际数字大小来判断可见性。pg将txid空间一分为二,对于某个特定的txid,其后约21亿个txid属于未来,均不可见;其前约21亿个txid属于过去,均可见。例如对于txid=4的事务,从2到2^31+4均为可见事务(即n+1到n+2^31);从2^31+5到3均为可见事务(即n+2^31+1到n-1)。

PostgreSQL中是使用2^31取模的方法来进行事务的比较,所以同一数据库中两个事务之间的年龄差最多为2^31,即20亿。

Postgres数据库中有几个特殊的事务ID,如下所示:

  • 0:表示无效的事务ID
  • 1:系统表初始化的事务ID,比所有普通的事务ID都要旧。
  • 2:冻结的事务ID,比任何普通的事务ID都要旧。

普通的事务ID是从3开始的。

冻结事务:

PG为了保证同一数据库中最新和最旧的两个事务之间年龄差不超过2^31,即20亿,引入了冻结(freeze)机制。

在9.4之前的版本中,freeze实现的方法很简单,那就是直接将符合条件的元组的t_xmin设置为2,这样就对所有普通事务可见。该元组原来对应的txid相当于被回收了,经过不断处理,就可以控制一个数据库的最老和最新的事务年龄不超过20亿。这样做的问题是当前可见的数据页需要全部扫描,带来大量的I/O操作。另外需要更新的元组需要更新xmin,产生大量脏页。在9.4版本之后,PG对冻结进行了一些改进,主要改进如下:

1、只更新元组头结点的t_infomask为HEAP_XMIN_FROZEN,表示该元组已经被冻结过(frozen)。

2、有些插入操作,如大批量copy数据,insert等,会直接将记录置为frozen。

3、如果整个page所有记录已经frozen,则在vm文件中标记为FROZEN,冻结清理会跳过该页,减少IO扫描。




举报

相关推荐

0 条评论