本文主要是介绍PostgreSQL10基础(7)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 | 181911792 | 81911785 | 0 | 2 | 2
(2 rows)# update test set name='new' where id=2;
UPDATE 1dd=# select txid_current(),xmin,xmax,* from test;txid_current | xmin | xmax | id | name
--------------+----------+------+----+------81911792 | 81911784 | 0 | 1 | 181911792 | 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 | 181911793 | 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 | 181911794 | 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
这篇关于PostgreSQL10基础(7)MVCC的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!