MySQL多版本并发控制机制源码分析

47次阅读
没有评论

共计 2575 个字符,预计需要花费 7 分钟才能阅读完成。

本篇内容主要讲解“MySQL 多版本并发控制机制源码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“MySQL 多版本并发控制机制源码分析”吧!

MVCC(多版本并发控制机制)

隔离性也可以被称作并发控制、可串行化等。谈到并发控制首先想到的就是锁,MySQL 通过使用两阶段锁的方式实现了更新的可串行化,同时为了加速查询性能,采用了 MVCC(Multi Version Concurrency Control)的机制,使得不用锁也可以获取一致性的版本。

Repeatable Read

MySQL 的通过 MVCC 以及 (Next-Key Lock) 实现了可重复读 (Repeatable Read), 其思想(MVCC) 就是记录数据的版本变迁,通过精巧的选择不同数据的版本从而能够对用户呈现一致的结果。如下图所示:

上图中,(A=50|B=50)的初始版本为 1。

1. 事务 t1 在 select A 时候看到的版本为 1,即 A =50

2. 事务 t2 对 A 和 B 的修改将版本升级为 2, 即 A =0,B=100

3. 事务 t1 再此 select B 的时候看到的版本还是 1, 即 B =50

这样就隔离了版本的影响,A+ B 始终为 100。

Read Commit

而如果不通过版本控制机制,而是读到最近提交的结果的话,则隔离级别是 read commit, 如下图所示:

在这种情况下,就需要使用锁机制 (例如 select for update) 将此 A,B 记录锁住,从而获得正确的一致结果, 如下图所示:

MVCC 的优势

当我们要对一些数据做一些只读操作来检查一致性,例如检查账务是否对齐的操作时候,并不希望加上对性能损耗很大的锁。这时候 MVCC 的一致性版本就有很大的优势了。

MVCC(实现机制)

本节就开始谈谈 MVCC 的实现机制, 注意 MVCC 仅仅在纯 select 时有效(不包括 select for update,lock in share mode 等加锁操作, 以及 updateinsert 等)。

select 运行栈

首先我们追踪一下一条普通的查询 sql 在 mysql 源码中的运行过程,sql 为(select * from test);

其运行栈为:

由于 mysql 默认隔离级别是 repeatable_read(RR), 所以 read_record 重载为 rr_sequential(当前我们并不关心 select 通过 index 扫描出 row 之后再通过 condition 过滤的过程)。继续追踪:

让我们看下该函数内部: 

bool lock_clust_rec_cons_read_sees(const rec_t* rec /* 由 innodb 扫描出来的一行 */,....){ ... //  从当前扫描的行中获取其 *** 修改的版本 trx_id(事务 id) trx_id = row_get_rec_trx_id(rec, index, offsets); //  通过参数 (一致性快照视图和事务 id) 决定看到的行快照  return(read_view_sees_trx_id(view, trx_id)); }

read_view 的创建过程

我们先关注一致性视图的创建过程, 我们先看下 read_view 结构:

然后通过 debug,发现创建 read_view 结构也是在上述的 rr_sequential 中操作的,继续跟踪调用栈:

我们看下 row_search_for_mysql 里的一个分支: 

row_search_for_mysql: //  这边只有 select 不加锁模式的时候才会创建一致性视图  else if (prebuilt- select_lock_type == LOCK_NONE) { //  创建一致性视图  trx_assign_read_view(trx); prebuilt- sql_stat_start = FALSE; }

上面的注释就是 select for update(in share model)不会走 MVCC 的原因。让我们进一步分析 trx_assign_read_view 函数:

好了,终于到了创建 read_view 的主要阶段, 主要过程如下图所示:

代码过程为:

MySQL 多版本并发控制机制源码分析

行版本可见性:

由上面的 lock_clust_rec_cons_read_sees 可知, 行版本可见性由 read_view_sees_trx_id 函数判断:

MySQL 多版本并发控制机制源码分析

其实上述函数就是一个二分法,read_view 其实保存的是当前活跃事务的所有事务 id, 如果当前行版本对应修改的事务 id 不在当前活跃事务里面的话,就返回 true, 表示当前版本可见,否则就是不可见, 如下图所示。

MySQL 多版本并发控制机制源码分析

接上述 lock_clust_rec_cons_read_sees 的返回:

MySQL 多版本并发控制机制源码分析

undolog 搜索可见版本的过程

我们现在考察一下 row_sel_build_prev_vers_for_mysql 函数: 

row_sel_build_prev_vers_for_mysql |-row_vers_build_for_consistent_read

主要是调用了 row_ver_build_for_consistent_read 方法返回可见版本:

MySQL 多版本并发控制机制源码分析

整个过程如下图所示:

MySQL 多版本并发控制机制源码分析

至于 undolog 怎么恢复出对应版本的 row 记录就又是一个复杂的过程了,由于篇幅原因,在此略过不表。

read_view 创建时机再讨论

在创建一致性视图的 row_search_for_mysql 的代码中

MySQL 多版本并发控制机制源码分析

trx_assign_read_view 中由这么一段代码

MySQL 多版本并发控制机制源码分析

所以综合这两段代码,即在一个事务中,只有 *** 次运行 select(不加锁)的时候才会创建一致性视图, 如下图所示:

MySQL 多版本并发控制机制源码分析

笔者构造了此种场景模拟过,确实如此。

MVCC 和锁的同时作用导致的一些现象

MySQL 是通过 MVCC 和二阶段锁 (2PL) 来兼顾性能和一致性的,但是由于 MySQL 仅仅在 select 时候才创建一致性视图,而在 update 等加锁操作的时候并不做如此操作,所以就会产生一些诡异的现象。如下图所示:

MySQL 多版本并发控制机制源码分析

如果理解了 update 不走一致性视图(read_view),而 select 走一致性视图(read_view),就可以很好解释这个现象。如下图所示:

MySQL 多版本并发控制机制源码分析

到此,相信大家对“MySQL 多版本并发控制机制源码分析”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-18发表,共计2575字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)