PostgreSQL技术大讲堂 - 第21讲:行可见性规则

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 从小白到专家,PostgreSQL技术大讲堂 - 第21讲:行可见性规则

PostgreSQL从小白到专家,是从入门逐渐能力提升的一个系列教程,内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容,希望对热爱PG、学习PG的同学们有帮助,欢迎持续关注CUUG PG技术大讲堂。

第21讲:行可见性规则

内容1:PostgreSQL事务id介绍

内容2:PostgreSQL DML操作原理

内容3:事务快照在可见性规则中的作用

内容4:T_xmin状态对于可见性规则判断的重要度

内容5:常见的行可见性规则的介绍

内容6:实现闪回功能


TXID介绍

· 事务id(txid)

当一个事务开始时,PostgreSQL中的事务管理系统会为该事务分配一个唯一标识符,即事务ID(txid).PostgreSQL中的txid被定义为一个32位的无符号整数,也就是说,它能记录大约42亿个事务。通常txid对我们是透明的,但是我们可以利用PostgreSQL内部的函数来获取当前事务的txid。

事务ID用来标识一个事务的先后顺序,该顺序决定了锁申请的优先权,已经访问一张表时对行的可见性规则判断。

testdb=# SELECT txid_current();

txid_current

--------------

100

(1 row)


Tuples Structure

· 元组(行)结构

t_xmin保存插入此元组的事务的txid,它的状态是行可见性判断关键的依据。

t_xmax保存删除或更新此元组的事务的txid。如果此元组未被删除或更新,则t_xmax设置为0,这意味着无效,它的状态也是行可见性判断关键的依据。


DML操作原理

· Insertion

· Deletion

· Update

执行第一个更新命令时,通过将txid 100设置为t_xmax,逻辑上删除Tuple_1,然后插入Tuple_2。然后,将元组1的t_ctid重写为指向元组2。

当执行第二个UPDATE命令时,与第一个UPDATE命令一样,Tuple_2在逻辑上被删除,Tuple_3被插入。


事务状态

· 四种事务状态

IN_PROGRESS

COMMITTED

ABORTED

SUB_COMMITTED


Commit Log

· 事务状态记录方式

事务快照

· 事务快照概述

事务快照是一个数据集,用于存储有关单个事务在某个时间点上是否所有事务都处于活动状态的信息。在这里,活动事务表示它正在进行或尚未启动。txid_current_snapshot的文本表示为“xmin:xmax:xip_list”,组件描述如下:

Xmin:最早仍在活动的txid。所有以前的事务要么提交并可见,要么回滚并停止。

Xmax:第一个尚未分配的txid。截至快照时,所有大于或等于此值的txid尚未启动,此不可见。

xip_list:快照时的活动txid。该列表仅包含xmin和xmax之间的活动txid。

testdb=# SELECT txid_current_snapshot();

txid_current_snapshot

-----------------------

100:104:100,102

(1 row)

例如,在快照'100:104:100,102'中,xmin是'100',xmax是'104',xip_list是'100,102'。


可见性规则世界观

· 事务快照在可见性规则中的意义

富有哲理性的判断规则:过去发生过的为可见,将来未发生的为不可见。


行可见性判断重要因素

· 可见性判断的重要因素

可见性检查规则是一组规则,关键的判断因素有:t_xmin、t_xmax、clog和获取的事务快照确定每个元组是否可见。

T_xmin的三种状态ABORTED、IN_PROGRESS、COMMITTED是判断的第一前提条件。


ABORTED状态

· t_xmin =ABORTED

t_xmin =ABORTED,则判断此行不可见

/* t_xmin status = ABORTED */

Rule 1: IF t_xmin status is 'ABORTED' THEN

RETURN 'Invisible'

END IF


IN_PROGRESS状态

· t_xmin=IN_PROGRESS

t_xmin=IN_PROGRESS,当前事务可见,其它事务不可见

/* t_xmin status = IN_PROGRESS */

IF t_xmin status is 'IN_PROGRESS' THEN

IF t_xmin = current_txid THEN

Rule 2: IF t_xmax = INVALID THEN

RETURN 'Visible'

Rule 3: ELSE /* this tuple has been deleted or updated by the current transaction itself. */

RETURN 'Invisible'

END IF

Rule 4: ELSE /* t_xmin ≠ current_txid */

RETURN 'Invisible'

END IF

END IF


COMMITTED状态

· t_xmin=COMMITTED

t_xmin=COMMITTED,此状态判断时还得看t_xmax的值,如果t_xmax的值为0,则此行可见;如果不为0,那么判断时还得看t_xmax的状态是当前事务还是非当前事务,判断规则就比较复杂。

/* t_xmin status = COMMITTED */

IF t_xmin status is 'COMMITTED' THEN

Rule 5: IF t_xmin is active in the obtained transaction snapshot THEN

RETURN 'Invisible'

Rule 6: ELSE IF t_xmax = INVALID OR status of t_xmax is 'ABORTED' THEN

RETURN 'Visible'

ELSE IF t_xmax status is 'IN_PROGRESS' THEN

Rule 7: IF t_xmax = current_txid THEN

RETURN 'Invisible'

Rule 8: ELSE /* t_xmax ≠ current_txid */

RETURN 'Visible'

END IF

ELSE IF t_xmax status is 'COMMITTED' THEN

Rule 9: IF t_xmax is active in the obtained transaction snapshot THEN

RETURN 'Visible'

Rule 10: ELSE

RETURN 'Invisible'

END IF

END IF

END IF


可见性判断概述

· 可见性判断示例


R6判断规则

· T3 时根据规则6进行判断

Rule6(Tuple_1)Status(t_xmin:199) = COMMITTED ∧ t_xmax = INVALIDVisible

T_xmin=commit,并且t_xman=0,该行对于所有的事务均可见


R7与R2判断规则

· T5时事务ID为200的根据规则7、2进行判断

Rule7(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = IN_PROGRESS ∧ t_xmax:200 = current_txid:200 Invisible

Rule2(Tuple_2): Status(t_xmin:200) = IN_PROGRESS ∧ t_xmin:200 = current_txid:200 ∧ t_xmax = INVAILD Visible

此时块中包含两行数据,对于事务id=200来说,它的判断规则是:

第一行数据根据规则7判断,t_xmin=commit,同时(t_xmax=200)= IN_PROGRESS,并且t_xmax:200为当前事务id,则第一行判断为不可见。

第二行根据规则2判断, t_xmin=commit,同时(t_xmax=200)为当前事务id,并且t_xmax为无效,则该行可见。

testdb=# -- txid 200

testdb=# SELECT * FROM tbl;

name

------

Hyde


R8与R4判断规则

· T5时事务ID为201的根据规则8、4进行判断

Rule8(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = IN_PROGRESS ∧ t_xmax:200 ≠ current_txid:201 Visible

Rule4(Tuple_2): Status(t_xmin:200) = IN_PROGRESS ∧ t_xmin:200 ≠ current_txid:201 Invisible

此时块中包含两行数据,对于事务id=201来说,它的判断规则是:

第一行数据根据规则8判断,t_xmin=commit,同时(t_xmax=200)= IN_PROGRESS,并且t_xmax:200不是当前事务id,则第一行判断为可见。

第二行根据规则2判断, (t_xmax=200)状态为IN_PROGRESS,同时t_xmin不是当前事务id,则该行不可见。

testdb=# -- txid 201

testdb=# SELECT * FROM tbl;

name

--------

Jekyll


R10与R6判断规则

· T7时事务ID为201的根据规则10、6进行判断(READ COMMITED)

Rule10(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = COMMITTED ∧ Snapshot(t_xmax:200) ≠ active Invisible

Rule6(Tuple_2): Status(t_xmin:200) = COMMITTED ∧ t_xmax = INVALID Visible

T7时事务id为200的提交了事务,对于事务id=201来说,它的判断规则是:

第一行根据规则10判断,t_xmin=commit,同时(t_xmax=200)= COMMITTED ,并且Snapshot(t_xmax:200) 状态为非活动,则第一行判断为不可见。

第二行根据规则6判断, (t_xmax=200)状态为COMMITTED ,同时t_xmax为无效,则该行可见。

testdb=# -- txid 201 (READ COMMITTED)

testdb=# SELECT * FROM tbl;

name

------

Hyde


R9与R5判断规则

· T7时事务ID为201的根据规则9、5进行判断(REPEATABLE READ)

Rule9(Tuple_1): Status(t_xmin:199) = COMMITTED ∧ Status(t_xmax:200) = COMMITTED ∧ Snapshot(t_xmax:200) = active Visible

Rule5(Tuple_2): Status(t_xmin:200) = COMMITTED ∧ Snapshot(t_xmin:200) = active Invisible

如果事务的隔离级别是可重复读,那么其判断规则就会发生变化,T7时事务id为200的提交了事务,对于事务id=201来说,它的判断规则是:

第一行根据规则9判断,t_xmin=commit,同时(t_xmax=200)= COMMITTED ,并且Snapshot(t_xmax:200) 状态为活动,则第一行判断为可见。

第二行根据规则5判断, t_xmax=200状态为COMMITTED , Snapshot(t_xmin:200) 为活动,则该行不可见,通过该规则,不会导致幻读发生。

testdb=# -- txid 201 (REPEATABLE READ)

testdb=# SELECT * FROM tbl;

name

--------

Jekyll


提高判断效率

· Hint Bits

由于进行行可见性判断时都要查看存储在clog中t_xmin和t_xmax的状态,为了解决对clog频繁访问这个问题,PostgreSQL使用了提示位,如下所示:

#define HEAP_XMIN_COMMITTED 0x0100 /* t_xmin committed */

#define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */

#define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */

#define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */


实现闪回功能

PostgreSQL由于数据的更新时新旧数据都保留在数据块中,那么如果要实现像Oracle一样的闪回查询功能应该是可以实现的,只要在判断时先判断该查询是否是闪回查询,然后再根据一个针对闪回查询的可见性规则判断就可以实现。

如果实现闪回查询,那么涉及到Vacuum操作时需要考虑更多的因素,需要有一个参数来设置块中被删除的行保留的时间长度。

以上就是【PostgreSQL从小白到专家】第21讲 - 行可见性规则 的内容,欢迎一起探讨交流,往期视频及文档,联系CUUG

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
5月前
|
监控 关系型数据库 MySQL
10亿数据如何最快速插入MySQL:技术干货分享
【8月更文挑战第2天】在大数据时代,处理并快速插入数十亿条数据到MySQL数据库是许多企业面临的关键挑战。本文将深入分享一系列高效的技术策略和实战经验,帮助读者优化这一过程,确保数据能够快速、准确地进入数据库系统。
245 1
|
1月前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
2月前
|
监控 前端开发 Java
【技术开发】接口管理平台要用什么技术栈?推荐:Java+Vue3+Docker+MySQL
该文档介绍了基于Java后端和Vue3前端构建的管理系统的技术栈及功能模块,涵盖管理后台的访问、登录、首页概览、API接口管理、接口权限设置、接口监控、计费管理、账号管理、应用管理、数据库配置、站点配置及管理员个人设置等内容,并提供了访问地址及操作指南。
|
2月前
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
167 3
|
3月前
|
XML 关系型数据库 MySQL
MySQL 导出某些数据的技术详解
MySQL 导出某些数据的技术详解
190 2
|
4月前
|
存储 关系型数据库 MySQL
技术解析:MySQL中取最新一条重复数据的方法
以上提供的两种方法都可以有效地从MySQL数据库中提取每个类别最新的重复数据。选择哪种方法取决于具体的使用场景和MySQL版本。子查询加分组的方法兼容性更好,适用于所有版本的MySQL;而窗口函数方法代码更简洁,执行效率可能更高,但需要MySQL 8.0及以上版本。在实际应用中,应根据数据量大小、查询性能需求以及MySQL版本等因素综合考虑,选择最合适的实现方案。
460 6
|
3月前
|
关系型数据库 MySQL 数据库
MySQL技术深度解析:每次最大插入条数探秘
MySQL技术深度解析:每次最大插入条数探秘
65 0
|
3月前
|
关系型数据库 MySQL 数据库管理
MySQL技术指南:如何更改数据字段的前几位数字
MySQL技术指南:如何更改数据字段的前几位数字
75 0
|
3月前
|
消息中间件 监控 关系型数据库
MySQL数据实时同步到Elasticsearch:技术深度解析与实践分享
在当今的数据驱动时代,实时数据同步成为许多应用系统的核心需求之一。MySQL作为关系型数据库的代表,以其强大的事务处理能力和数据完整性保障,广泛应用于各种业务场景中。然而,随着数据量的增长和查询复杂度的提升,单一依赖MySQL进行高效的数据检索和分析变得日益困难。这时,Elasticsearch(简称ES)以其卓越的搜索性能、灵活的数据模式以及强大的可扩展性,成为处理复杂查询需求的理想选择。本文将深入探讨MySQL数据实时同步到Elasticsearch的技术实现与最佳实践。
234 0
|
5月前
|
SQL 存储 关系型数据库
mysql加索引真的会锁表吗?揭秘背后的技术细节与规避策略
【8月更文挑战第16天】在数据库管理中,添加索引能大幅提升查询效率。MySQL执行此操作时的锁定行为常引起关注。文章详细解析MySQL中索引添加时的锁定机制及其原理。不同存储引擎及SQL语句影响锁定策略:MyISAM需全表锁定;InnoDB提供更灵活选项,如使用`ALTER TABLE... LOCK=NONE`可在加索引时允许读写访问,尽管可能延长索引构建时间。自MySQL 5.6起,在线DDL技术可进一步减少锁定时间,通过`ALGORITHM=INPLACE`和`LOCK=NONE`实现近乎无锁的表结构变更。合理配置这些选项有助于最小化对业务的影响并保持数据库高效运行。
621 4
下一篇
开通oss服务