前言
阅读之前,您可能需要了解MVCC和事务快照相关文章。
文章目录
一、tuple行头信息简介
二、PostgreSQL事务状态
三、tuple可见性判断规则
四、归纳总结
一、tuple行头信息简介
tuple行头简述
前面的文章中,介绍过pg中通过事务id来标记一个数据行的版本,即之前我们提及的t_xmin、t_xmax。
tuple头部信息记录着数据行的t_xmin、t_xmax、t_cid、t_xvac等信息。在可见性判断里面比较重要的是:
t_xmin:表示tuple的插入事务id。
t_xmax:表示tuple的被删除或被锁住的事务id。
typedef struct HeapTupleFields{TransactionId t_xmin; /* inserting xact ID */TransactionId t_xmax; /* deleting or locking xact ID */union{CommandId t_cid; /* inserting or deleting command ID, or both */TransactionId t_xvac; /* old-style VACUUM FULL xact ID */} t_field3;} HeapTupleFields;详见:postgresql-12.2\src\include\access\htup_details.h
二、Postgresql事务状态
1.事务状态和可见性判断关系
当我们在事务中发起一个SQL语句查询数据的时候,表记录tuple某个版本对当前事务是否可见,是在特定的事务快照下,通过读取tuple的xid事务状态信息来进行判断的。
2.事务提交日志clog
PostgreSQL 中定义的事务状态有四种:
1).处理中:in progress
2).已提交:committed
3).异常终止:aborted
4).子事务已提交:sub committed
以上事务状态会持久化到 $PGDATA/pg_xact目录下clog文件。同时,为了减少对clog的IO请求,会cache部分事务状态到shared_buffers中,并且在tuple的t_infomask字段标记相关的事务状态。
/** Possible transaction statuses --- note that all-zeroes is the initial* state.** A "subcommitted" transaction is a committed subtransaction whose parent* hasn't committed or aborted yet.*/typedef int XidStatus;#define TRANSACTION_STATUS_IN_PROGRESS 0x00#define TRANSACTION_STATUS_COMMITTED 0x01#define TRANSACTION_STATUS_ABORTED 0x02#define TRANSACTION_STATUS_SUB_COMMITTED 0x03详见:postgresql-12.2\src\include\access\clog.h
3.tuple中的t_infomask
通过获取xid在t_infomask的标记信息,可以不用访问clog信息就可以判断tuple版本对当前事务是否可见。
t_infomask有以下与可见性相关的标志位:
#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */#define HEAP_XMIN_FROZEN (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */#define HEAP_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */详见:postgresql-12.2\src\include\access\htup_details.h
比如标记HEAP_XMIN_COMMITTED为真,并且HEAP_XMAX_INVALID为假,则说明这行是新插入的行,是可见的,这时就不需要到clog中查询xmin的事务状态和xmax的事务状态了。
但如果HEAP_XMIN_COMMITTED没有设置,此时xmin对应的事务是否已提交是不知道的,这种情况仍然需要到clog中去判断xmin的状态,对于HEAP_XMAX_COMMITTED同样如此。
三、可见性判断规则
1.通过事务快照判断
首先,在判断tuple可见性的时候,需要给定一个xid,语句检索数据的时候会自动获取tuple的t_xmin、t_xmax;
然后,判断该xid和快照xmin:xmax:xip_list之间的关系,最主要目的是判断该xid是否还在in progress状态。
关于transaction snapshot中xmin和xmax,我们可以参考源码对SnapshotData结构体中xmin和xmax的定义:
typedef struct SnapshotData{...TransactionId xmin; /* all XID < xmin are visible to me */TransactionId xmax; /* all XID >= xmax are invisible to me */...}详见:\postgresql-12.2\postgresql-12.2\src\include\utils\snapshot.h
总的来说:
1)小于snapshot中的xmin:该tuple属已结束事务,对当前事务可见。
2)大于等于snapshot中的xmax:该tuple属未来事务,对当前事务不可见。
3)如果在snapshot的xip_list之中,即[xmin,xmax)之间:则进一步查看xid的事务状态来判断tuple是否可见。
结合前面介绍的4种事务状态,如果不考虑sub committed的情况,大致的判断逻辑像下面这个样子:
/* t_xmin status = ABORTED */Rule 1: IF t_xmin status is 'ABORTED' THENRETURN 'Invisible'END IF/* t_xmin status = IN_PROGRESS */IF t_xmin status is 'IN_PROGRESS' THENIF t_xmin = current_txid THENRule 2: IF t_xmax = INVALID THENRETURN 'Visible'Rule 3: ELSE /* this tuple has been deleted or updated by the current transaction itself. */RETURN 'Invisible'END IFRule 4: ELSE /* t_xmin ≠ current_txid */RETURN 'Invisible'END IFEND IF/* t_xmin status = COMMITTED */IF t_xmin status is 'COMMITTED' THENRule 5: IF t_xmin is active in the obtained transaction snapshot THENRETURN 'Invisible'Rule 6: ELSE IF t_xmax = INVALID OR status of t_xmax is 'ABORTED' THENRETURN 'Visible'ELSE IF t_xmax status is 'IN_PROGRESS' THENRule 7: IF t_xmax = current_txid THENRETURN 'Invisible'Rule 8: ELSE /* t_xmax ≠ current_txid */RETURN 'Visible'END IFELSE IF t_xmax status is 'COMMITTED' THENRule 9: IF t_xmax is active in the obtained transaction snapshot THENRETURN 'Visible'Rule 10: ELSERETURN 'Invisible'END IFEND IFEND IF更多参考详见:http://www.interdb.jp/pg/pgsql05.html
四、归纳总结
如果对Oracle熟悉(Read committed),上面的判断逻辑应该比较容易理解,其实我们可以简单概括为:
1.别人事务的增删改,如果事务未提交,增删改的行记录最新状态在当前事务会话中无法读取。
2.自己当前事务的增删改,即使未提交,增删改的行记录最新状态在自己的当前事务内,当然能读取。
3.无论是别人事务还是自己当前事务发起的增删改,如果事务异常中断,则所有会话都无法读取。
结合之前判断逻辑,这里顺便借鉴Hironobu SUZUKI整理的规则供学习参考。其中“∧”表示“and”,“∨”表示“or”:
Rule 1: If Status(t_xmin) = ABORTED => InvisibleRule 2: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax = INVAILD => VisibleRule 3: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax ≠ INVAILD => InvisibleRule 4: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin ≠ current_txid => InvisibleRule 5: If Status(t_xmin) = COMMITTED ∧ Snapshot(t_xmin) = active => InvisibleRule 6: If Status(t_xmin) = COMMITTED ∧ (t_xmax = INVALID ∨ Status(t_xmax) = ABORTED) => VisibleRule 7: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax = current_txid => InvisibleRule 8: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax ≠ current_txid => VisibleRule 9: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) = active => VisibleRule 10: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) ≠ active => Invisible

参考资料
1.http://www.interdb.jp/pg/pgsql05.html
2.https://www.postgresql.org/docs/12/index.html

I Love PG
关于我们
中国开源软件推进联盟PostgreSQL分会(简称:PG分会)于2017年成立,由国内多家PG生态企业所共同发起,业务上接受工信部产业发展研究院指导。PG分会致力于构建PG产业生态,推动PG产学研用发展,是国内一家PG行业协会组织。
技术文章精彩回顾 PostgreSQL学习的九层宝塔 PostgreSQL职业发展与学习攻略 搞懂PostgreSQL数据库透明数据加密之加密算法介绍 一文读懂PostgreSQL-12分区表 一文搞懂PostgreSQL物化视图 PostgreSQL源码学习之:RegularLock Postgresql源码学习之词法和语法分析 2019,年度数据库舍 PostgreSQL 其谁? Postgres是最好的开源软件 PostgreSQL是世界上最好的数据库 从Oracle迁移到PostgreSQL的十大理由 PG活动精彩回顾 创建PG全球生态!PostgresConf.CN2019大会盛大召开 首站起航!2019“让PG‘象’前行”上海站成功举行 走进蓉城丨2019“让PG‘象’前行”成都站成功举行 中国PG象牙塔计划发布,首批合作高校授牌仪式在天津举行 群英论道聚北京,共话PostgreSQL 相聚巴厘岛| PG Conf.Asia 2019 DAY0、DAY1简报 相知巴厘岛| PG Conf.Asia 2019 DAY2简报 独家|硅谷Postgres大会简报 PostgreSQL线上沙龙第一期精彩回顾 PostgreSQL线上沙龙第二期精彩回顾 PostgreSQL线上沙龙第三期精彩回顾 PostgreSQL线上沙龙第四期精彩回顾 PostgreSQL线上沙龙第五期精彩回顾 PG培训认证精彩回顾 关于中国PostgreSQL培训认证,你想知道的都在这里! 首批中国PGCA培训圆满结束,首批认证考试将于10月18日和20日举行! 中国首批PGCA认证考试圆满结束,203位考生成功获得认证! 中国第二批PGCA认证考试圆满结束,115位考生喜获认证! 请查收:中国首批PGCA证书! 重要通知:三方共建,中国PostgreSQL认证权威升级! 一场考试迎新年 | 12月28日,首次PGCE中级认证考试开考! 近500人参与!首次PGCE中级、第三批次PGCA初级认证考试落幕! 通知:PostgreSQL技术能力电子证书上线!





