NOTE

2.2 PostgreSQL MVCC

1. 总体规则 - 在PostgreSQL中,每一个事务都会得到一个被称作为 XID 的事务ID - 可以通过 select cast(txid current() as text) 查询 - 这里说的事务不仅仅是被 BEGIN - COMMIT 包裹的一组语句,还包括单条的 insert 、 up

Database创建于 更新于 约 2 分钟读完historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 总体规则
  • 在PostgreSQL中,每一个事务都会得到一个被称作为 XID 的事务ID
    • 可以通过select cast(txid_current() as text)查询
    • 这里说的事务不仅仅是被 BEGIN - COMMIT 包裹的一组语句,还包括单条的insertupdate或者delete语句
  • 当一个事务开始时,PostgreSQL递增XID,然后把它赋给这个事务。

2026 注:这里是简化理解。PostgreSQL 的事务 ID 可以延迟到真正需要时再分配;行可见性也不能只按 XID 大小判断,还要结合快照中的 xmin / xmax / 活跃事务集合以及事务提交状态。旧的 txid_* 查询接口目前主要用于兼容。

  • PostgreSQL还在系统里的每一行记录上都存储了事务相关的信息,这被用来判断某一行记录对于当前事务是否可见。

见下图例:

注意如上说明针对的是已提交的事务而言,未提交的事务无论如何对其他事务都是不可见的。

2. 例子
2.1. 插入
  • 如果事务ID比已提交行的xmin大,那么这个事务可以看到这一行
  • 如果事务ID比已提交行的xmin小,那么能否看到取决于隔离级别。
    • RC级别,当前时间取当前正在执行的sql的时候,那么看得到这一行
    • RR/S级别,当前时间取当前正在运行的事务的最开始的时间,那么看不到这一行
2.2. 删除
  • 如果事务ID比已提交行的xmax大,那么这个事务看不到已经被删除的这一行(即看得到这个删除)
  • 如果事务ID比已提交行的xmax小,那么能否看到取决于隔离级别。
    • RC级别,当前时间取当前正在执行的sql的时候,那么这个事务看不到已经被删除的这一行(即看得到这个删除)
    • RR/S级别,当前时间取当前正在运行的事务的最开始的时间,那么看得到这一行
2.3. 更新
  • 更新的本质就是删除+插入,被删除的那一行的xmax被设置为当前事务ID,新插入的一个的xmin被设置为当前事务ID
  • 能否看到删除的一行见上面的删除
  • 能否看到插入的一行见上面的插入
3. 底层原理
3.1. 定义多版本的数据

使用HeapTupleHeaderData中的xmin和xmax字段来标示元组的版本号

  • xmin表示insert时的事务ID
  • xmax表示update/delete时的事务ID
3.2. 定义事务快照

快照就是某时刻下数据库所有元组的xmin和xmax满足一定条件的值的集合。 SnapshotData中也有两个字段xmin,xmax,这两个值的定义如下:

  • 查看当前所有的未提交并活跃的事务,存储在数组中,选取最小的XID,记录在快照的xmin中
  • 选取所有已提交事务中最大的XID,加1后记录在xmax中
3.3. 定义快照拍摄时机

拍摄时机是根据用户定义的隔离级别决定的,三个事务隔离等级拍摄快照的时机不同,但其判断条件都是一样的

  • 若xmin等于当前事务ID,则包含所有xmax=0(未被删除)的元组。
  • 若与xmin相等的事务ID对应的事务已经被提交,则包含所有xmax=0或xmax为当前事务ID的元组。
正在加载有帮助数量