用pageinspect浅探下PostgreSQL的MVCC

用pageinspect浅探下PostgreSQL的MVCC

Whoami:5年+金融、政府、医疗领域工作经验的DBA
Certificate:OCP、PCP
Skill:Oracle、Mysql、PostgreSQL
Platform:CSDN、墨天伦、公众号(呆呆的私房菜)

业务范围:数据库安装部署、日常维护、主备切换、故障处理、性能优化、技术培训等。

需要的伙伴或者商业合作请移步 公众号【呆呆的私房菜】获取联系方式。

01 MVCC概述

到底什么是MVCC呢?

  1. MVCC即多版本并发控制, 是一种用于处理数据库中并发操作的机制;
  2. 在MVCC中,每个数据库事务在读取数据时会看到一个特定的版本,这使得事务之间可以同时进行读写操作,并且不会相互干扰。每个事务可以操作自己的数据版本,从而实现了更高的并发性和更好的性能;
  3. MVCC核心思想是对每个修改此操作,不是直接在原始数据上进行修改,而是创建一个新的数据版本,并将修改操作应用于新版本,这样其它事务仍可以访问旧版本数据,而不会受到正在进行的修改的影响。只有在事务提交时,新版本的数据才会替代旧版本,从而实现数据的一致性。
  4. MVCC在数据库中起作用的原理是通过使用版本号、时间戳或类似的标识来管理数据版本,并通过一定的规则来决定哪些版本对于每个事务是可见的。

02 MVCC实现方法

第一种: 写新数据时,元数据移到一个单独的位置,如回滚段中,其他用户读数据时,从回滚段中把元数据读出来。
第二种: 写新数据时,原数据不删除,而是把新数据插入进来。

03 PostgreSQL MVCC

PostgreSQL数据库是通过把原数据保留在数据文件中,新插入一条数据来实现多版本并发功能的。

我们可以通过pageinspect插件来窥视PostgreSQL的多版本控制工作过程。

shell 复制代码
## 为实现MVCC,PostgreSQL数据库的每张表上都存在4个系统字段:
## 1. xmin:表示记录的第一个可见事务的 XID;
## 2. xmax:表示记录的最后一个修改它的事务的 XID;
## 3. cmin:表示命令ID的最小值;
## 4. cmax:表示命令ID的最大值。

postgres=# create extension pageinspect;
CREATE EXTENSION

postgres=# create table a1 (id int);
CREATE TABLE

postgres=# insert into a1 values (1),(2);
INSERT 0 2

## 不收集统计信息前,看不到当前元组使用的数据页和元组数量
postgres=# select relname, relpages, reltuples from pg_class where relname = 'a1';
 relname | relpages | reltuples
---------+----------+-----------
 a1      |        0 |        -1
(1 row)

## 收集统计信息
postgres=# analyze a1;
ANALYZE

## 表a1占用了1个数据页,一共有2个元组
testdb=# select relname, relpages, reltuples from pg_class where relname = 'a1';
 relname | relpages | reltuples 
---------+----------+-----------
 a1      |        1 |         2
(1 row)

## heap_page_items函数用于获取数据库堆表页上条目的信息
## lp: 指向下一条记录的指针。如果这是页上的最后一条记录,这个值通常是指向页末尾的偏移量。
## lp_off: 记录在页上的偏移量。
## lp_flags: 记录的一些状态标志,比如是否是脏页(dirty)。
## lp_len: 记录的长度。
## t_xmin: 插入这条记录的事务的最小事务 ID(XID)。如果这个值是 InvalidTransactionId(0),表示这条记录是可见的。
## t_xmax: 最后一次删除或更新这条记录的事务的事务 ID。如果这个值是 0,表示这条记录没有被当前事务删除或更新。
## t_field3: 这个字段通常用于存储额外的事务信息,但具体内容取决于 PostgreSQL 的版本。
## t_ctid: 当前记录的复合索引,包含块号和行号。
## t_infomask2: 一个掩码,用于存储记录的额外信息,比如是否是只读副本。
## t_infomask: 另一个掩码,用于存储记录的元数据信息,比如是否是压缩的或是否包含 OID。
## t_hoff: 指向记录头信息的偏移量。
## t_bits: 一个位图,用于存储记录的可见性和其他信息。
## t_oid: 如果记录包含 OID 列,则这个字段存储该值。
## t_data: 记录的实际数据,通常以字节序列的形式存储。
## 输出解读:
## 1. 两条记录的t_xmin,说明是由同个事务插入的
## 2. t_xmax没有记录代表没有事务更新或删除这条记录
## 3. t_ctid显示了记录的当前位置
## postgres=# select * from heap_page_items(get_raw_page('a1',0));
 lp | lp_off | lp_flags | lp_len |   t_xmin   | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid |   t_data   
----+--------+----------+--------+------------+--------+----------+--------+-------------+------------+--------+--------+-------+------------
  1 |   8160 |        1 |     28 | 2146483941 |      0 |        0 | (0,1)  |           1 |       2304 |     24 |        |       | \x01000000
  2 |   8128 |        1 |     28 | 2146483941 |      0 |        0 | (0,2)  |           1 |       2304 |     24 |        |       | \x02000000
(2 rows)

## 更新一条数据
postgres=# update a1 set id = 22 where id = 2;
UPDATE 1

## 输出解读:
## 1. 新增了一条xid为2146483943的记录,并且记录了更新后的数据
## 2. 被更新的记录并没有被删除,而是被标记为旧版本,数据仍保存在原数据文件中。
postgres=# select * from heap_page_items(get_raw_page('a1',0));
 lp | lp_off | lp_flags | lp_len |   t_xmin   |   t_xmax   | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid |   t_data   
----+--------+----------+--------+------------+------------+----------+--------+-------------+------------+--------+--------+-------+------------
  1 |   8160 |        1 |     28 | 2146483941 |          0 |        0 | (0,1)  |           1 |       2304 |     24 |        |       | \x01000000
  2 |   8128 |        1 |     28 | 2146483941 | 2146483943 |        0 | (0,3)  |       16385 |        256 |     24 |        |       | \x02000000
  3 |   8096 |        1 |     28 | 2146483943 |          0 |        0 | (0,3)  |       32769 |      10240 |     24 |        |       | \x16000000
(3 rows)

动动手,做做试验吧!通过上边小小的实验我们就可以看到PostgreSQL的多版本并发控制的实现原理啦!

相关推荐
樽酒ﻬق12 小时前
PostgreSQL、MariaDB和MySQL的异同及应用:企业级数据库选型指南
数据库·postgresql·mariadb
huangsu_12321 小时前
java+postgresql+swagger-单表批量和循环insert、delete操作(八)
java·开发语言·数据库·postgresql
文牧之2 天前
PostgreSQL 的统计信息
运维·数据库·postgresql
程序员学习随笔2 天前
PostgreSQL技术内幕28:触发器实现原理
数据库·postgresql
m0_653031363 天前
PostgreSQL技术大讲堂 - 第86讲:数据安全之--data_checksums天使与魔鬼
postgresql
qq_339282234 天前
PostgreSQL-常用命令
数据库·postgresql·oracle
江节胜-胜行全栈AI4 天前
PostgreSQL-中文字段排序-修改字段的排序规则
数据库·postgresql
1988我想和这个世界谈谈5 天前
若依前后端分离版本从mysql切换到postgresql数据库
数据库·postgresql
北漂老男孩6 天前
MySQL、Oracle 和 PostgreSQL 是三种主流的关系型数据库的主要原理性差异分析
数据库·mysql·postgresql·oracle