PostgreSQL10基础(7)MVCC

本文深入解析MVCC(多版本并发控制)机制,介绍其在PostgreSQL等主流数据库中的应用,探讨内部可见性计算原理,通过实例展示事务隔离级别下数据读取的一致性,以及MVCC带来的性能优势和磁盘空间占用问题。

参考书籍: 《PostgreSQL10 High Performance》

MVCC即Multi Version Concurrency Control多版本并发控制,为提升多用户访问同样的数据而设计,性能优于锁定。被广泛用于诸多主流数据库。

内部可见性计算

当一个事务创建时,数据库会更新一个事务ID计算器,通常叫做XID。

  • 当插入一行或更新数据时,一个新行被创建(更新也会创建新行),该新行有一个字段insertion XID(通常称作xmin),记录了当前事务ID
  • 当删除数据时,每个被删除行有个delete XID(通常称作xmax),当行未被删除时值为空
select txid_current(),xmin,xmax,id from test

txid_current()函数返回当前查询的XID

如果一个查询开始,行数据被找到的条件为

(查询XID >= xmin) && ((查询XID <= xmax) || 查询XID is null)

每个数据库客户会话都允许同时修改表,但他们只有在事务提交后才对其他会话可见。

示例

会话1启动事务并更新数据但不提交
# begin;
BEGIN

# select txid_current(),xmin,xmax,* from test;
 txid_current |   xmin   | xmax | id | name
--------------+----------+------+----+------
     81911792 | 81911784 |    0 |  1 | 1
     81911792 | 81911785 |    0 |  2 | 2
(2 rows)

# update test set name='new' where id=2; 
UPDATE 1

dd=# select txid_current(),xmin,xmax,* from test;
 txid_current |   xmin   | xmax | id | name
--------------+----------+------+----+------
     81911792 | 81911784 |    0 |  1 | 1
     81911792 | 81911792 |    0 |  2 | new
(2 rows)
会话2 查询数据

因会话1未提交,会话2XID大于修改数据的XMAX值,因此看不到最新版本数据,只能看到老版本未修改的数据

# select txid_current(),xmin,xmax,* from test;
 txid_current |   xmin   |   xmax   | id | name
--------------+----------+----------+----+------
     81911793 | 81911784 |        0 |  1 | 1
     81911793 | 81911785 | 81911792 |  2 | 2
(2 rows)

会话1 提交

提交后xmax被清空

# commit;
COMMIT

如果会话没有提交而是回滚,则直接删除新版本数据即可。

会话2再次查询(事务中)或新会话 查询数据

因为xmax被清空,因此可以查到提交的数据

# select txid_current(),xmin,xmax,* from test;
 txid_current |   xmin   | xmax | id | name
--------------+----------+------+----+------
     81911794 | 81911784 |    0 |  1 | 1
     81911794 | 81911792 |    0 |  2 | new
(2 rows)

dd=# commit;
COMMIT

更新数据行的实际过程

  • 读入原行数据
  • 根据update修改数据字段
  • 将新数据行及其XID写入到新的磁盘
  • 旧数据行在不再被使用后,可以被Vacuum删除

删除数据行的实际过程

  • 标记原行数据为删除,并更新XID
  • 旧数据行在不再被使用后,可以被Vacuum删除

Heap only tuples(HOT)

上文提到更新和删除的过程,HOT在特定条件下允许直接重用更新和删除操作数据行后的磁盘空间。

例如更新行没有更新任何索引字段,如果新数据行可以被当前数据行所在数据页剩余空间容纳下时。将触发一个数据块上的mini vacuum。正常的Vacuum需要更新数据heap和Index,而mini vacuum只更新数据heap,因此称为heap only。

pg_stat_user_tables视图记录了表上所有更新次数n_tup_upd和HOT更新次数n_tup_hot_upd

MVCC优缺点

优点

最大程度避免了锁定,读数据不会与写数据发生冲突,读不会阻塞写,写也不会阻塞读。

缺点

  • 占用了磁盘空间,需要进行Vacuum清扫
    • 更新时使用了新的磁盘,老数据未被删除
    • 删除时老数据未被真正删除磁盘
  • 要当心不可重复读和脏读问题

事务ID环绕

事务ID是32比特,大约20亿个ID,超出则会变为0。MVVC的可见机制将会出现问题。

为了解决问题

  • 每个数据库和每张表都有一个引用XID,可见于pg_class表relfrozenxid字段,该字段记录本表或数据库最小XID,小于该值得XID都见被置为保留的冻结ID,Vacuum将处理这些XID
MVCC(多版本并发控制)是一种常见的数据库并发控制技术,它允许多个事务同时访问数据库,而不会互相干扰。下面是MySQL、PostgreSQL和Oracle的MVCC方式的对比: 1. MySQL MVCC方式: MySQL使用基于时间戳的MVCC方式。每个事务在开始时会分配一个唯一的时间戳,然后每个数据行都会存储一个创建时间和一个过期时间。当一个事务要读取一行数据时,MySQL会比较事务的时间戳和该数据行的创建和过期时间,如果该数据行的创建时间早于事务的时间戳,并且过期时间晚于事务的时间戳,则该数据行可见。 2. PostgreSQL MVCC方式: PostgreSQL使用基于快照的MVCC方式。每个事务在开始时会创建一个快照,这个快照包含了数据库中所有数据的当前状态。每个数据行都会存储一个版本号和一个指向该版本的指针。当一个事务要读取一行数据时,PostgreSQL会比较事务的快照和该数据行的版本号,如果该数据行的版本号早于事务的快照,则该数据行不可见。 3. Oracle MVCC方式: Oracle使用基于undo的MVCC方式。每个事务在开始时会创建一个undo段,这个undo段用于存储所有被修改的数据的历史版本。每个数据行都会存储一个SCN(系统变更号),这个SCN表示该数据行的版本号。当一个事务要读取一行数据时,Oracle会比较事务的SCN和该数据行的SCN,如果该数据行的SCN早于事务的SCN,则该数据行可见。 总的来说,MySQL的MVCC方式相对简单,但是在高并发情况下可能会出现性能问题。PostgreSQLMVCC方式比较复杂,但是可以提供更好的并发性能。Oracle的MVCC方式则是一种比较成熟的实现,但是需要额外的存储空间来存储undo段。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值