从Oracle到PG-PostgreSQL的MVCC机制简介

2020-06-17 00:00:00 数据 版本 事务 记录 更改

PostgreSQL和Oracle、MySQL等RDBMS一样,都有自己的并发控制机制。而并发控制的目的是为了在多个事务同时运行时保持事务ACID属性。
MVCC即Multi-version concurrence control首字母缩写,MVCC会为每个数据更改操作创建数据块或数据行的新版本,同时保留旧版本,主要优点是:
‘readers don’t block writers,and writers don’t block readers’
即“读不会阻塞写,而写也不会阻塞读”。
在Oracle中,多版本控制MVCC通过回滚段实现,当行记录row发生更改的时候,先将数据块的旧版本将写入回滚段,随后将新数据覆写入原data block数据块区域。在读取数据的时候,通过比对scn来读取合适的数据版本。


Oracle 19C Read Consistency in the Read Committed

相对Oracle来说,PostgreSQL的MVCC则使用更简单的方法来实现。当行记录tuple发生更改时候,新数据直接插入到原来的data page中。在读取数据的时候,PostgreSQL通过可见性规则读取合适的数据版本。


Transaction ids in PostgreSQL

简单来说,PostgreSQL和Oracle在MVCC的实现上存在以下主要区别:
Oracle:基于SCN,块级别,循环undo segment实现,支持闪回功能,存在大事务回滚、快照过旧ORA-01555问题。
PostgreSQL:基于事务编号txid,行级别,无需undo,不支持闪回,大事务可瞬间回滚,存在数据块(block page)空间及性能消耗问题。

值得提出的是,去年Oracle中出现的SCN大值预警问题,在PostgreSQL中通过txid循环复用来规避。
Oracle查看当前scn:
SQL> select current_scn from v$database;
CURRENT_SCN
--------------------
698823298
SQL>

PostgreSQL查看当前事务ID:
(postgres@[local]:5432)[akendb01]#select txid_current();
txid_current
--------------
636
(1 row)

–查看行记录tuple 1的txid:
(postgres@[local]:5432)[akendb01]#insert into table01 values(1,'aken01');
INSERT 0 1
(postgres@[local]:5432)[akendb01]#select id,name, ctid,xmin,xmax from public.table01;
id | name | ctid | xmin | xmax
----+--------+-------+------+------
1 | aken01 | (0,1) | 636 | 0

上面的行记录Tuple 1,即id=1的事务ID如下:

  • t_xmin:被设置为636,表示该tuple的版本在txid=636的事务中被插入。
  • t_xmax :被设置为 0,表示该tuple的版本未发生过deleted or updated.
  • t_ctid:被设置为(0.1),表示该tuple位于page 0的存储位置。这里的t_ctid和Oracle的rowid相似。

–下面对行记录tuple进行更改:
(postgres@[local]:5432)[akendb01]#insert into table01 values(2,'aken02');
INSERT 0 1
(postgres@[local]:5432)[akendb01]#update table01 set name='aken03' where id=2;
UPDATE 1

–查看tuple 2的事务txid:
(postgres@[local]:5432)[akendb01]#select id,name, ctid,xmin,xmax from public.table01;
id | name | ctid | xmin | xmax
----+--------+-------+------+------
1 | aken01 | (0,1) | 636 | 0
2 | aken02 | (0,2) | 638 | 639
2 | aken03 | (0,2) | 639 | 0
(3 rows)
(postgres@[local]:5432)[akendb01]#

上面的行记录Tuple 2,即id=2的事务ID如下:
版本1:旧版本:

  • t_xmin:被设置为638,表示该tuple的版本在txid=638的事务中被插入。
  • t_xmax :被设置为 639,表示该tuple的版本发生了deleted or updated,为旧版本.
  • t_ctid:被设置为(0.2),表示该tuple位于page 0的位置。这里的t_ctid和Oracle的rowid相似。

版本2:新版本:

  • t_xmin:被设置为639,表示该tuple的版本在txid=639的事务中被插入。
  • t_xmax :被设置为0,表示该tuple的版本未发生过deleted or updated.
  • t_ctid:被设置为(0.2),表示该tuple位于page 0的位置。这里的t_ctid和Oracle的rowid相似。

欢迎关注头条号查看Aken更多相关文章:
toutiao.com/c/user/5453
参考资料:
postgresql.org/docs/12/
docs.oracle.com/en/data
interdb.jp/pg/pgsql05.h
—本文完—

相关文章