1
什么是可见性指标?
用户通过UPDATE将数据记录从‘A’更改为‘B’。 PostgreSQL 通过INSERT新记录‘B’的方式处理,同时将记录‘A’标记为‘不可见’。 系统中同时存在这两条记录,但‘B’是可见的,‘A’则不可见。 已被删除或不可见的记录也被称为‘死’元组。 VACUUM进程的职责之一是清除这些‘死’元组以释放空间。
2
可见性指标
Transaction ID xmin xmax cid transaction snapshot CLOG (Commit Log) hintbit
3
事务 ID
xmin, xmax, cid 和hintbit
这些指标被归为一类,因为它们都存储在每个堆数据元组的头部,并且每个数据元组可能具有不同的值,从而导致不同的可见性检查结果。下面的图像显示了它们存储在元组头部的位置:

这是删除该堆数据元组的事务ID。 如果元组头部含有有效的、已提交的 xmax 值,通常说这个元组是“已删除的”或“不可见的”。
这是在事务中插入此数据元组的命令ID。 主要用于确定当前事务中的可见性。 如果一个事务包含 SELECT 和其他 DML 查询(INSERT、UPDATE 和 DELETE),那么可以使用cid 来确定一个数据元组是在 SELECT 之前还是之后被插入或删除。
这是一个标志字段,用于存储来自CLOG的查询结果,这样PostgreSQL就不必每次都查找CLOG。CLOG指的是提交日志,下文会详细解释。 如果hintbit设置了HEAP_XMIN_COMMITTED标志,这意味着插入此元组的事务ID(即xmin)已提交。 如果PostgreSQL可以直接从hintbit获取这些信息,那么它可以节省一些查找CLOG的时间,从而提高性能。 可能的hintbit标志值如下:

4
CLOG (Commit Log)
COMMITTED IN_PROGRESS ABORTED SUB_COMMITTED

5
事物快照
[xmin, xmax, xip_list]xmin: 仍然活跃的最小事务ID — 小于这个值的事务已经提交或回滚。 xmax: 已提交或回滚的最大事务ID + 1 — 大于或等于这个值的事务尚未提交或回滚。 xip_list: 正在进行中的事务号列表 — 应该大于xmin并且小于xmax。
postgres=# BEGIN;Postgres*# INSERT INTO mytable VALUES('A');Postgres*# SELECT txid_current();txid_current--------------747(1 row)
postgres=# BEGIN;postgres=# INSERT INTO mytable VALUES('B');postgres=# SELECT txid_current();txid_current--------------748(1 row)
postgres=# BEGIN;Postgres*# INSERT INTO mytable VALUES('C');Postgres*# SELECT txid_current();txid_current--------------749(1 row)
postgres=# BEGIN;Postgres*# INSERT INTO mytable VALUES('A');Postgres*# SELECT txid_current();txid_current--------------747(1 row)
postgres=# BEGIN;postgres=# INSERT INTO mytable VALUES('B');postgres=# SELECT txid_current();txid_current--------------748(1 row)
postgres=# BEGIN;Postgres*# INSERT INTO mytable VALUES('C');Postgres*# SELECT txid_current();txid_current--------------749(1 row)Postgres*# COMMIT;postgres=# select pg_current_snapshot();pg_current_snapshot---------------------747:750:747,748(1 row)
747 是仍然活跃的最小事务ID。 750 是已提交或已中止的最大事务ID + 1(749 + 1)。 747 和 748 是仍在进行中的事务。
C 能够看到由事务ID小于750的数据元组插入的数据,但不能看到事务ID为747和748的数据,因为它们仍在进行中(尚未提交或回滚)。 C 不能看到未来插入的数据元组(事务ID大于750的数据)。 C 能够看到由自己在事务749中插入的数据元组,因为它刚刚提交了这个事务。
postgres=# BEGIN;Postgres*# INSERT INTO mytable VALUES('A');Postgres*# SELECT txid_current();txid_current--------------747(1 row)Postgres*# select pg_current_snapshot();pg_current_snapshot---------------------747:750:748(1 row)
postgres=# BEGIN;postgres=# INSERT INTO mytable VALUES('B');postgres=# SELECT txid_current();txid_current--------------748(1 row)postgres=*# select pg_current_snapshot();pg_current_snapshot---------------------747:750:747(1 row)
postgres=# BEGIN;Postgres*# INSERT INTO mytable VALUES('C');Postgres*# SELECT txid_current();txid_current--------------749(1 row)Postgres*# COMMIT;postgres=# select pg_current_snapshot();pg_current_snapshot---------------------747:750:747,748(1 row)
6
确定可见性
xmin、xmax、cid 和 hintbit 存储在元组头部。 快照(snapshot)、事务ID在启动事务时由事务管理器提供。 CLOG 存储在共享内存中


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




