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来读取合适的数据版本。
![f83ec0d135d7ccb85a4fb76d8670378d.png](https://i-blog.csdnimg.cn/blog_migrate/c9ab537d6c2ae3a71c49fc9a3e4398c1.jpeg)
Oracle 19C Read Consistency in the Read Committed
相对Oracle来说,PostgreSQL的MVCC则使用更简单的方法来实现。当行记录tuple发生更改时候,新数据直接插入到原来的data page中。在读取数据的时候,PostgreSQL通过可见性规则读取合适的数据版本。
![4761d41d835acf62aacdf7dbbae6a1d7.png](https://i-blog.csdnimg.cn/blog_migrate/8649c64a5886194e149c0edbb845b164.jpeg)
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更多相关文章:https://www.toutiao.com/c/user/54536888148/#mid=1610143870006285
参考资料:https://www.postgresql.org/docs/12/mvcc.htmlhttps://docs.oracle.com/en/database/oracle/oracle-database/19/cncpthttp://www.interdb.jp/pg/pgsql05.html
—本文完—