PostgreSQL的MVCC vs InnoDB的MVCC

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB PostgreSQL 版,企业版 4核16GB
推荐场景:
HTAP混合负载
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: PostgreSQL的MVCC vs InnoDB的MVCC

PostgreSQL的MVCC vs InnoDBMVCC

   任何一个数据库最主要功能之一是可扩展。如果不删除彼此,则尽可能较少锁竞争从而达到这个目的。由于readwriteupdatedelete是数据库中最主要且频繁进行的操作,所以并发执行这些操作时不被阻塞则显得非常重要。为了达到这种目的,大部分数据库使用多版本并发控制(Multi-Version Concurrency Control)这种并发模型。这种模型能够将竞争减少到最低限度。


MVCC是什么


   Multi Version Concurrency Control ( MVCC)是这样的一种算法:通过对同一个对象维护多个版本,提供一种很好的并发控制技术,这种技术能够使READWRITE操作不发生冲突。这里的WRITE指的是UPDATEDELETE,不包含Insert是因为新插入的记录可以通过各自的隔离级别进行保护。每个WRITE操作使对象产生一个新版本,每个并发读操作依赖于隔离级别读取对象不同的版本。由于READWRITE操作同一个对象的不同版本,所以这些操作不需要将对象完全锁住,因此这些操作能够并发执行。当然当两个并发事务WRITE同一个记录时,这些锁竞争还是会存在的。

   当前大部分数据库系统都支持MVCC。这个算法的核心是对相同对象维护不同版本,因此不同数据库创建并维护多版本的方式不同,其实现方式也不同。相应地,数据库操作和数据存储也发生变化。

实现MVCC最常见的方法:PostgreSQL使用的方法、InnoDBOracle的使用方法。下面我们会详细讨论PGInnoDB的实现方式。


PostgreSQL中的MVCC


为了支持多版本,PG对每个对象(PG术语:Tuple)增加了额外的字段:

1、xmin:进行插入或更新操作事务的事务IDUPDATE中,对tuple的新版本分配该事务ID

2、xmax:进行删除或更新操作事务的事务IDUPDATE中,对当前存在的tuple分配该事务ID。新创建的tuple,该字段默认为null

PostgreSQL将所有数据存储在HEAP中(每页默认8KB)。新记录的xmin为创建该记录的事务的事务ID;老版本(进行updatedelete)其xmax为进行操作的事务的ID。会有一个链表将老版本和新版本连接起来。在回滚的过程中,老版本记录可以被重用;依赖于隔离级别,READ语句读取一个老版本记录进行返回。

   例如下面两条记录:T1(值为1)、T2(值为2),通过下面3步对记录的创建进行演示:

 

   从图中可以看出,数据库中初始时存在两个记录:12

   第二步,将2更新为3。此时创建一个新值,并存放到同一个存储区域的下一个位置。老版本2为其xmax分配该事务的ID,并且指向最新的版本记录。

   同理,第三步,当T1被删除时,对记录进行虚拟删除(为其xmax分配当前事务ID),该操作不存在创建新记录版本。

   下面,通过实例讲解每个操作如何创建多版本,不用加锁如何实现事务的隔离级别。下面例子中使用默认隔离级别READ COMMITTED”。


INSERT


每次insert一个记录,都会新创建一个tuple并将其存储到表文件的页中。

可以看到:

1、Session-A开启一个事务,其事务ID495

2、Session-B开启一个事务,其事务ID496

3、Session-A插入一个tuple,存储到HEAP

4、tuplexmin495,而xmaxnull

5、由于Session-A的事务没有提交,session-B看不到第3步插入的值

6、Session-A提交

7、都可以看到新插入的tuple


UPDATE


PostgreSQLUPDATE不是“IN-PLACE”更新,不会将现有对象更新替换为新值,而是新创建一个新对象。因此UPDATE涉及以下几步:

1、将当前对象标记为deleted

2、插入对象的一个新版本

3、将对象的老版本指向新版本

因此,即使许多记录保持不变,HEAP也会占用空间,就像新插入另一个记录一样。

如上所示:

1、Session-A开启一个事务,其事务ID497

2、Session-B开启一个事务,其事务ID498

3、Session-A更新一个现有记录

4、Session-A可以看到tuple的最新版本而Session-B看到另一个老版本。Session-A看到新记录的xmin497,xmaxnullSession-B看到老版本xmin495xmax497Session-A的事务ID。这两个tuple版本都存在HEAP中,如果空间允许甚至存在同一页中。

5、Session-A提交事务,老版本消失

6、现在所有会话都可以看到记录的同一个版本。


DELETE


DELETE操作和UPDATE类似,只是不会添加一个新版本。如UPDATE,只是将当前对象标记为已删除。

1、Session-A开启一个事务,事务ID499

2、Session-B开启一个事务,事务ID500

3、Session-A删除现有记录

4、Session-A看不到当前事务已删除的记录;Session-B看到老版本,其xmax499499的事务删除的该记录

5、Session-A提交事务,老版本记录消失

6、所有会话都看不到之前的老版本

可以看到,这些操作都不会直接删除现有记录,如果需要会添加一个附加版本。

我们来看看SELECT在多版本中怎么执行:依赖于隔离级别,SELECT需要读取tuple的所有版本直到找到合适的tuple。假设有一个tuple T1,被更新为新版本T1,然后再被更新为T1’’

1、SELECT操作进入这个表的heap中,首先检查T1,如果T1xmax事务已提交,查找该tuple的下一个版本

2、T1也被提交,查找下一个版本

3、最后找到T1’’看到xmax未提交或者为null,然后T1’’xmin可见,最后读取T1’’这个tuple

可以看到需要遍历该tuple3个版本才能找到合适的可见版本,直到VACUUM进程回收了打上delete标签的记录。


InnoDB中的MVCC


为了支持多版本,InnoDB对行记录又额外维护了几个字段:

1、DB_TRX_ID:插入或更新航记录的事务的事务ID

2、DB_ROLL_PTR:即回滚指针,指向回滚段中的undo log record

PostgreSQL相比,InnoDB也会创建行记录的多版本,但是存储老版本的方式不同。

InnoDB将行记录的老版本存放到独立的表空间/存储空间(回滚段)。和PostgreSQL不同,InnoDB仅将行记录最新版本存储到表的表空间中,而将老版本存放到回滚段。回滚段中的undo log作用:用来进行回滚操作;依赖于隔离级别,进行多版本读,读取老版本。

例如,两行记录:T1(值为1),T2(值为2),可以通过下面3步说明新记录的创建过程:

从上图可以看到,初始时,表中有两条记录12

第二阶段,行记录T22被更新为3。此时记录创建一个新版本并替代老版本。老版本存储到回滚段(注意,回滚段中的数据仅包含更改值,即delta value),同时新版本行记录中的回滚指针指向回滚段中的老版本。和PostgreSQL不同,InnoDB更新是“IN-PLACE”。

 

同理,第三步,删除T1然后将其标记为虚拟删除(仅在行记录指定的一个bit位上打上delete标签)并在回滚段中插入一个对应的新版本。同样回滚指针指向回滚段中undo log

 

从表面上看,所有操作表象与PostgreSQL相同,只是多版本在内部存储方式不同。

 

MVCC:PostgreSQL vs InnoDB


下面分析PostgreSQLInnoDBMVCC主要不同在哪几方面:

1、老版本的大小

PostgreSQL仅更新tuple老版本的xmax,因此老版本的大小和相应插入的记录大小相同。这意味着,如果一个older tuple3个版本,那么他们大小都相同(如果更新的值大小不同,每次更新时实际大小就不同)。

InnoDB的老版本存储到回滚段,且比对应的插入记录小,因为InnoDB仅将变化的值写到undo log

2、INSERT操作

   INSERT时,InnoDB会向回滚段写入额外的记录,而PostgreSQL仅在UPDATE中创建新版本。

3、回滚时恢复老版本

回滚时,PostgreSQL不用任何特定内容,需注意老版本的xmax等于update该记录的事务ID。因此在并发快照中该记录认为是alive的直到该事务ID的事务提交。

InnoDB,一旦回滚,需要重新构造对象的老版本。

4、回收老版本占用的空间

PG中,老版本占用的空间仅在没有并发快照使用时才可以被回收,此时被认为dead。然后VACCUM可以回收空间。VACCUM可以手动触发也可以依赖于配置在后台任务中触发。

InnoDBundo log分为INSERT UNDOUPDATE UNDO。事务提交后,就会立即释放INSERT UNDO。当没有其他并发快照使用时,才可以释放UPDATE UNDOInnoDB没有显示VACUUM操作但是有类似的PURGE回收undo log

5、延迟vacuum的影响

如前所示,PostgreSQL延迟vacuum存在很大影响。即使频繁执行delete,它将会引起表膨胀造成占用的存储空间暴增。这还会造成到达一个点后,需要执行一个高额代价的操作VACUUM FULL

6、表膨胀时的顺序扫描

即使所有记录都是dead状态,PostgreSQL的顺序扫描也会扫描对象所有的老版本,直到执行vacuumdead的记录删除。这是PG中常见且经常讨论的问题。主要PG将一个tuple的所有老版本都存储到同一个存储区域。

InnoDB,除非需要,否则不需要读取undo log。如果所有undo记录都已失效,那么只需要读取所有对象的最新版本既可。

7、索引

PostgreSQL独立存储索引,并将索引连接到HEAP中的真实数据。因此即使没有更改索引,有时也需要更新索引。随后这个问题被HOTHeap Only Tuple)解决,但是仍有限制,如果相同页空间不足,则退回到正常UPDATE操作。

InnoDB由于使用聚集索引,不会有这样的问题。


结论


PostgreSQLMVCC有一些缺点,尤其是具有频繁UPDATE/DELETE负载时,会引起表膨胀。因此决定选择PG时,需要慎重配置VACUUM

PG社区已经意识到这个问题,已经开始涉及基于undoMVCC(暂命名为ZHEAP),我们在未来版本可以看到这个特性。


原文


https://severalnines.com/blog/comparing-data-stores-postgresql-mvcc-vs-innodb

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
1月前
|
存储 缓存 关系型数据库
⑩⑧【MySQL】InnoDB架构、事务原理、MVCC多版本并发控制
⑩⑧【MySQL】InnoDB架构、事务原理、MVCC多版本并发控制
129 0
|
11天前
|
存储 关系型数据库 MySQL
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
MySQL数据库进阶第六篇(InnoDB引擎架构,事务原理,MVCC)
|
1月前
|
关系型数据库 MySQL 数据处理
MySQL vs. PostgreSQL:选择适合你的开源数据库
在当今信息时代,开源数据库成为许多企业和开发者的首选。本文将比较两个主流的开源数据库——MySQL和PostgreSQL,分析它们的特点、优势和适用场景,以帮助读者做出明智的选择。
|
11月前
|
存储 SQL 缓存
PostgreSQL mvcc可见性判断
PostgreSQL mvcc可见性判断
87 0
|
8月前
|
存储 关系型数据库 MySQL
如何选择最适合你的数据库解决方案:PostgreSQL VS MySQL 技术选型对比
如何选择最适合你的数据库解决方案:PostgreSQL VS MySQL 技术选型对比
236 1
|
8月前
|
存储 关系型数据库 Go
深入理解 PostgreSQL 中的 MVCC(多版本并发控制)机制
深入理解 PostgreSQL 中的 MVCC(多版本并发控制)机制
134 0
|
8月前
|
存储 关系型数据库 MySQL
MySQL引擎:InnoDB VS MyISAM
MySQL引擎:InnoDB VS MyISAM
|
算法 关系型数据库 MySQL
简述Mysql InnoDB的MVCC机制
简述Mysql InnoDB的MVCC机制
134 0
简述Mysql InnoDB的MVCC机制
|
算法 测试技术 分布式数据库
PolarDB-X 数据分布解读 :Hash vs Range
Hash与Range对于数据库,到底意味着什么?作为应用,又该如何选择?PolarDB-X的Hash分区与其它数据库的Hash分区有什么区别?
271 1
|
关系型数据库 MySQL 数据库
MySQL 中 MyISAM vs. InnoDB
 MyISAM 是 MySQL 的默认数据库引擎(5.5 版本之前),由早期的 ISAM 改良而来,虽然性能极佳,但却有一个致命缺点:不支持事务处理(transaction),后来 MySQL 导入 InnoDB 以强化参照完整性与并发违规处理机制,后来就逐渐取代 MyISAM 成为 MySQL 的默认数据库引擎,现在最新版本的 MyISAM 也支持事务处理。
MySQL 中 MyISAM vs. InnoDB