MySQL-MVCC多版本并发控制的实现方式及原理

什么是多版本并发控制?其实这个主要目的,就是为了解决在数据库高并发下的读写冲突。在此之前有两个概念一个为快照读,一个为当前读。

当前读:例如update、delete、insert这些DML语句,为了读取到最新的数据,会对读取的记录进行加锁读取,保证其他事务不能对其进行修改。

快照读:像select这样的读取,即快照读,不加锁不阻塞,但是前提是,非串行化隔离级别下,MVCC多版本并发控制,由多个版本进行控制,不同的事务读取的可能是多个版本,不一定是读取的最新数据,但是相互之间能尽量不受到影响。

1 MVCC如何实现的?

MVCC实现方式主要由三大部分组成:
(1)数据行的三个隐藏字段
(2) undo log
(3) Read view(读视图)

2 数据行的三个隐藏字段

数据行在我们原始列的基础上,还有三个隐藏的字段:
(1)DB_TRX_ID
(2)DB_RALL_PTR
(3)DB_ROW_ID

2.1 DB_TRX_ID

DB_TRX_ID,即事务ID,每个事务对数据行进行修改后,都会记录此事务的ID,例如我们开启事务后,分配的事务id为1,对t1表进行插入,字段为name=a,age=10。在插入后字段为name 列为a,age为10,而隐藏字段DB_TRX_ID,就会等于1。如果此时事务2进来,对此行记录进行修改,那么此时在修改的过程中,隐藏字段DB_TRX_ID就会变成了2,随后提交。


image.png

2.2 DB_RALL_PTR

DB_RALL_PTR,这个隐藏字段主要存储的为undo log中 rollback segment 旧版本记录的指针,还是上方的例子。分配的事务id为1,对t1表进行插入,字段为name=a,age=10。在插入后字段为name 列为a,age为10,而隐藏字段DB_TRX_ID,就会等于1。而DB_RALL_PTR因为是新纪录插入,假设回滚记录为null,或者是回滚后为删除此条记录,如果此时事务2进来,对这行记录进行update,将age修改为了11,那么此时name列为a,age列为11,DB_TRX_ID列就等于2了,而DB_RALL_PTR记录的则是insert插入的那条数据,undo log中的记录。但是其中有一点概念啊,insert与其他dml语句不同,在插入后commit后,很大概率就会从undo log中删除了。这里只是为了举例DB_RALL_PTR的记录。

image.png

2.3 DB_ROW_ID

什么是DB_ROW_ID,他的作用其实是在我们表没有主键的情况下,生成的隐藏主键列,然后用这个列去建立的聚集索引。他在这里,主要的作用其实是与DB_RALL_PTR的配合,DB_RALL_PTR存储的指针,其实就是undo log中 rollback segment中的历史版本记录的的DB_ROW_ID。所以我们可以把上方的图进行一个完善。就是如下的样子:

image.png

小知识:其实还有一个flag的隐藏字段,也提一嘴,他的作用是,我们delete某条数据的时候,并不是真的把数据删除了,而是在flag字段上打上了一个被删除的标签。

3 MVCC中undo log的作用

undo log我们都知道,是回滚日志,为什么在MVCC中也被用上了是怎么用上的呢?前面页提到了,MVCC快照读取记录的时候,不一定是最新的记录。这个不一定最新的记录指的就是去undo log中读取的记录。undo log又分为insert undo和update undo。两种也是存在一定的区别的。

insert undo:顾名思义,就是insert事务插入时产生的undo日志,这部分日志在insert语句提交后,基本上也就从undo log中被丢弃了。

update undo:这种类型的undo,主要是update语句和delete语句产生的。delete或者update语句commit之后,undo日志不一定会被立即丢弃。有可能会等着给MVCC进行使用。但是为了节省磁盘空间,还会有一个专门的purge线程进行负责清理这部分数据。

小知识:undo log 的purge线程是如何清理数据的呢?其实当我们对一个记录进行delete后,不一定会被数据库立即删除,就像刚才提到的flag隐藏字段,只是将delete的这条记录打上了一个deleted_bit 等于true的标签,当打上标签的记录,被purge盯上后,purge会根据与read view进行比较后,再决定是否丢弃这部分数据。

4 Read view

什么是read view,从名称可以知道是读视图,简单说,他其实就是当事务进行快照读时,所产生的读视图。当一个事务开启快照读后,就会对当前数据库系统生成一个快照,这个快照会记录当前系统,所有活跃的事务ID,并进行维护,这就是读视图,事务ID为自增的,也就是说最大的事务ID就能代表最新的事务。

而MVCC的实现方式,就是通过读视图维护的事务ID与记录中隐藏字段的事务ID进行比较,来判断当前事务对该记录的可见性。从而实现的多版本并发控制。

4.1 Read view由几个关键的部分组成:

  1. m_ids:在生产读视图时,当前系统活跃的事务id列表,即没有提交的事务id。

  2. Min_trx_id:表示当前列表中,活跃的最小的事务id

  3. Max_trx_id:表示当前列表中(最大的事务id+1),也就是下一次系统分配的事务id。

  4. Creator_trx_id:表示生成该read view的事务id。当前事务id

4.2 Read view比对可见性的方法

上面我们理解了read view还有隐藏字段,以及undo log,那么他们配合后是如何进行比对,可见性,实现多版本并发控制呢?分为四种情况:

第一种:当TRX-id与当前开启快照读的事务id一致,可以断定,是自己修改自己读,可以见。

第二种:当TRX-id小于当前read view种最小的活跃事务id,表示这个记录早就被修改提交了,所以也可以直接获取最新记录

第三种:如果说,当TRX-id大于当前read view种最大的事务id+1,那则表示,这行记录是在你开启快照都之后被修改了。所以不可见,需要根据行记录种的RALL-PTR去undo log中找合适你这个事务id的数据

第四种:即不小于,也不大于等于,也不是当前事务id,那就要判断,这个trx-id的事务,是不是还在活跃列表中,如果在,那就是还没提交不可见,需要去找undo,如果不在,表示他已经提交了。可以获取数据。

4.3 举例

下方有五个事务,事务3和事务4开启了快照读,而事务5修改了这个记录并提交退出了了。那么快照都应该比较呢?还是这张表:


image.png

image.png

那么此时表会变成这样:

image.png

事务3:当事务开启了快照读,生成了读视图,当前事务3的trx_id为3,而现在read view列表中,活跃的id有,id1,id2,id3,id4。最小的id为1,最大的id为5+1,也就是6,首先与最小的进行比较,3是否小于1,不小于,下一个判断,是否大于等于6,也不大于,在进行判断事务id5,是否存在与列表中,如果在表示数据还没提交,不能读取,需要按照当前事务id3去undo log找历史版本的记录,如果不在,表示事务已经提交了,那么可以直接进行读取最新记录,也就是age=1。从上方图可以看出,事务5已经提交了,所以我们可以直接读取最新记录。

事务4:与事务3原理一样
另一种情况:如果此时来了一个事务7修改了这条记录还没提交:

image.png

然后开启快照都后,read view活跃事务列表是这样的:

image.png

随后事务8,拿着trx_id 7进行与活跃列表比较,不小于4,下一个判断条件,是否大于等于9,不等于,判断是否存在7活跃列表,发现存在,那么不能获取当前记录,因为猜测事务7还没提交,所以只能获取上一个版本的信息。即age=1的数据。

4.4 MVCC原理图

image.png

5 MVCC与隔离级别的关系

在RC与RR不同的隔离级别下,进行快照读取的情况可能存在不同。RC为读已提交,只能读取到提交的数据,但是可能存在不可重复读和幻读,RR,可重复读级别,可能造成幻读。

MVCC快照读取在RC隔离级别下,每次快照读,都会生成一个新的read view,这样的话就可能导致,两次读取的数据不一致。但是在RR隔离级别下,相同的事务,只有第一次快照读的时候会产生read view,一直沿用,所以不会出现不可重复度的情况。

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

推荐阅读更多精彩内容