基于mysql简析MVCC机制

MVCC

  MVCC(Multi-Version Concurrency Control),直翻过来就是多版本并发控制。对MVCC对应的就是加锁的并发控制LBCC(Lock-Based Concurrency Control)。MVCC最大的好处就是读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能。这也是为什么现阶段,几乎所有的RDBMS,都支持了MVCC。
  MVCC是multiversion concurrency control的简称,也就是多版本并发控制,是个很基本的概念。MVCC的作用是让事务在并行发生时,在一定隔离级别前提下,可以保证在某个事务中能实现一致性读,也就是该事务启动时根据某个条件读取到的数据,直到事务结束时,再次执行相同条件,还是读到同一份数据,不会发生变化(不会看到被其他并行事务修改的数据)。MVCC是需要配合事务隔离级别的。
  有了 MVCC 就可以提高事务的并行度,因为可以利用锁机制实现资源控制而无需等待其他事务先执行。
在了解MVCC之前需要理解一下几个概念:

基础概念

在数据库并发读写的时候,多会话的读写可能会产生不一致的现象,MVCC就是为了避免这种情况,对数据库进行并发访问控制。避免脏读等现象最简单的一种方式就是加锁,达到读写串行,就不会产生脏读等现象,但是串行读写并发读写性能无法达到生产数据库环境要求。

MVCC实现原理

上述现象在数据库中大家经常看到,但是数据库到底是怎么实现的,深究的人就不多了。
其实原理很简单,InnoDB数据库就是通过UNDO和MVCC来实现的。
1. 旧数据存储在UNDO中,再通过DB_ROLL_PTR 回溯查找历史版本
首先InnoDB每一行数据还有一个DB_ROLL_PTR(回滚指针),用于指向该行修改前的上一个历史版本(InnoDB里,会将 row data修改前的旧数据存储在UNDO中)

图片.png

当插入的是一条新数据时,记录上对应的回滚段指针为NULL

图片.png

更新记录时,原记录将被放入到undo表空间中,并通过DB_ROLL_PTR指向该记录。session2查询返回的未修改数据就是从这个UNDO中返回的。MySQL就是根据记录上的回滚段指针及事务ID判断记录是否可见,如果不可见继续按照DB_ROLL_PTR继续回溯查找。
2. 通过read view判断行记录是否可见

具体的判断流程如下:
RR隔离级别下,在每个事务开始的时候,会将当前系统中的所有的活跃事务拷贝到一个列表中(read view)。
RC隔离级别下,在事务中的每个语句开始时,会将当前系统中的所有的活跃事务拷贝到一个列表中(read view) 。
然后按照以下逻辑判断事务的可见性


图片.png
图片.png

扩展一个Read View的数据结构记录版本数据,它有三个部分:
(1) 当前活跃的事务列表 ,即[101,102]
(2) Tmin ,就是活跃事务的最小值, 在这里 Tmin = 101
(3) Tmax, 是系统中最大事务ID(不管事务是否提交)加上1。 在这里例子中,Tmax = 103

现在来模拟一下这个快照读这个场景
首先假设t1表中的当前DB_TRX_ID为tx0

时间点 会话1 会话2 会话3
T1 start tx1
T2 start tx2
T3 select t1
T4 start tx3
T5 update t1;commit
T6 select t1
T7 update t1;commit
T8 select t1

先来谈RC级别各个时间线时内部发生的情况:
T1:会话1发起一个新事务
T2:会话2发起一个新事物
T3:会话1发起了select t1查询t1表,生成了一个事务列表(readview),把当前活动事务tx1,tx2放入readview中。查询到的该行记录DB_TRX_ID为tx0,tx0<tmin(即为tx1),直接将该行输出。
T4:会话3发起一个新事物
T5:会话2发起了update t1更新t1表并提交,把该行旧的记录复制到undo log中,该行记录的DB_TRX_ID更新为tx2,该行的DB_ROLL_PTR指向undo log中DB_TRX_ID为tx0旧的记录的位置,记录redo log。
T6:会话1发起select t1查询t1表,生成了一个事务列表(readview)把当前的活动事务tx1,tx3放入readview中。并查询到该行记录DB_TRX_ID为tx2,由于tx2<tmin(即为tx1)为"否"所以继续判断,tx2>=tmax(即为tx3+1)为"否",继续判断tx2在当前readview中为"否",所以直接将该行输出。
T7:会话3发起了update t1更新t1表并提交,把该行的记录复制到undo log中,该行记录的DB_TRX_ID更新为tx3,该行的DB_ROLL_PTR指向undo log中DB_TRX_ID为tx2旧记录位置,tx2旧的记录回滚指针继续指向tx0旧记录位置,记录redo。
T8:会话1发起select t1查询t1表,生成了一个事务列表(readview)把当前的互动事务tx1放入readview中。并查询到该行记录的DB_TRX_ID为tx3,由于tx3<tmin(即为tx1)为"否"所以继续判断,tx3>=tmax(即为tx3+1)为"否",继续判断tx3在当前readview为"否",所以直接输出。
再来谈RR级别各个时间线时内部发生的情况:
T1:会话1发起一个新事物
T2:会话2发起一个新事物
T3:会话1发起 select t1查询t1表,生产了一个事务列表(readview),把当前活动事务tx1,tx2放入readview中。查询到该行的记录DB_TRX_ID为tx0,tx0<tmin(即为tx1),直接将该行输出。
T4:会话3发起一个新事物
T5:会话2发起了update t1更新t1表并提交,把该行旧的记录复制到undo log中,该行记录的DB_TRX_ID更新为tx2,该行的DB_ROLL_PTR指向undo log中DB_TRX_ID为tx0的旧的记录位置,记录redo log。
T6:会话1发起select t1查询t1表,由于是RR隔离级别,所以利用第一次查询生成的readview,查询到该行记录DB_TRX_ID为tx2,由于tx2<tmin(即为tx1)为"否"所以继续判断,tx2>=tmax(即为tx3+1)为"否",继续判断tx2在readview中,结果为"是",所以沿着回滚指针找到上一行,将事务ID赋值给tid(tx0)。
T7:会话3发起update t1查询t1表并提交,把该行旧的记录复制到undo log中,该行记录的DB_TRX_ID更新为tx3,该行的DB_ROLL_PTR指向undo log中DB_TRX_ID为tx2的旧的记录位置,记录redo log。
T8:会话1发起select t1查询t1表,由于是RR隔离级别,所以利用第一次查询生成的readview,查询到该行记录DB_TRX_ID为tx3,由于tx3<tmin(即为tx1)为"否"所以继续判断,tx3>=tmax(即为tx2+1)为"是",沿着回滚指针找到上一行,将事务ID赋值给tid(tx2),继续循环知道找到tx0那行记录返回。

MVCC解决了什么问题

  • MVCC使得数据库读不会对数据加锁,普通的select请求不会加锁,提高了数据库的并发处理能力。
  • 借助MVCC,数据库可以实现RC,RR等隔离特性,用户可以查询到当前数据的前一个或者前几个历史版本。保证了ACID中的I特性(隔离性)。

转载及参考:

何登成的技术博客
MVCC原理探究及MySQL源码实现分析
隔离级别的实现原理

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容