什么是可见性指标?
用户通过UPDATE将数据记录从‘A’更改为‘B’。 PostgreSQL 通过INSERT新记录‘B’的方式处理,同时将记录‘A’标记为‘不可见’。 系统中同时存在这两条记录,但‘B’是可见的,‘A’则不可见。 已被删除或不可见的记录也被称为‘死’元组。 VACUUM进程的职责之一是清除这些‘死’元组以释放空间。
可见性指标
Transaction ID xmin xmax cid transaction snapshot CLOG (Commit Log) hintbit
事务 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标志值如下:
CLOG (Commit Log)
COMMITTED IN_PROGRESS ABORTED SUB_COMMITTED
事物快照
[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)
确定可见性
xmin、xmax、cid 和 hintbit 存储在元组头部。 快照(snapshot)、事务ID在启动事务时由事务管理器提供。 CLOG 存储在共享内存中
总结
关注公众号,了解更多社区动态
- 我们是谁 -
lvorySQL 是由瀚高基础软件股份有限公司主导研发的,一款基于 PostgreSQL 并深度兼容 Oracle 的开源数据库系统。IvorySQL 从底层代码层面深入把握开源技术的发展趋势,基于 PostgreSQL 16.3 的最新内核进行构建,同时提供了更加全面灵活的Oracle 兼容功能,具备高度的 SQL 和 PL/SQL 兼容性,能够满足企业对于数据库系统多样化和高兼容性的需求。
【IvorySQL技术指南】
Centos7 被停用!如何利用 Ora2Pg 将 Oracle 迁移至 IvorySQL?
聚焦 PGConf.dev 2024 聊聊 IvorySQL 最新应用实践
IvorySQL Operator | 一键部署IvorySQL集群,高效管理与个性化配置尽在掌控
pgvector扩展在IvorySQL Oracle兼容模式下的应用实践
IvorySQL 3.2 贡献独门秘籍,可以平滑迁移Oracle???
IvorySQL 3.2 :基于PG16.2,新增Oracle XML函数兼容功能
基于IvorySQL+Patroni+vip-manager构建高可用集群
备份恢复新体验!pgBackRest与IvorySQL的完美融合
最新版本!PG16.0最新内核,实现兼容Oracle数据库再升级
IvorySQL内核的Serverless数据库--HGNeon
IvorySQL