MVCC 实现原理详细解析

目录

1.1 定义

1.2 当前读和快照读

1.2.1 当前读

1.2.2 快照读

1.3 MVCC能解决什么问题 

1.4 MVCC实现原理

1.4.1 隐式字段

1.4.2 undo log日志

1.4.3 Read View

1.5 如何查询一条记录

1.6 redo log日志

1.7 总结

1.1 定义

MVCC(Multiversion concurrency control):多版本并发控制,并发访问(读或写)数据库时,对正在事务内处理的数据做多版本的管理。以达到用来避免写操作的堵塞,从而引发读操作的并发问题。

MVCCMySQL InnoDB 中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读

1.2 当前读和快照读

1.2.1 当前读

select lock in share mode (共享锁)

select for update;

update; insert; delete (排他锁)

这些操作都是一种当前读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

1.2.2 快照读

普通的select ... 操作都是快照读,读取的数据可能是历史快照数据,不是数据库最新的数据,快照读是通过 MVCC 和 Undo Log 实现的。(注意:快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读)

说白了 MVCC 就是为了实现读-写冲突不加锁,而这个读指的就是快照读, 而非当前读,当前读实际上是一种加锁的操作,是悲观锁的实现

1.3 MVCC能解决什么问题

  • 读写之间阻塞的问题,通过 MVCC 可以让读写互相不阻塞,读不相互阻塞,写不阻塞读,这样可以提升数据并发处理能力。
  • 降低了死锁的概率,这个是因为 MVCC 采用了乐观锁的方式,读取数据时,不需要加锁,写操作,只需要锁定必要的行。
  • 解决了一致性读的问题,当我们朝向某个数据库在时间点的快照是,只能看到这个时间点之前事务提交更新的结果,不能看到时间点之后事务提交的更新结果。

1.4 MVCC实现原理

1.4.1 隐式字段

1.例子:

1.4.2 undo log日志

1.例子:

2.基于UNDO_LOG版本连

3.为什么要有undo日志?

数据库事务未提交时,会将事务修改数据的镜像(即修改前的旧版本)存放到 undo 日志里,当事务回滚时,或者数据库奔溃时,可以利用 undo 日志,即旧版本数据,撤销未提交事务对数据库产生的影响。

  • 对于 insert 操作,undo 日志记录新数据的 PK(ROW_ID),回滚时直接删除;
  • 对于 delete/update 操作,undo 日志记录旧数据 row,回滚时直接恢复;
  • 他们分别存放在不同的 buffer 里。

一句话,undo 日志用于保障,未提交事务不会对数据库的 ACID 特性产生影响。

4.什么是回滚段?

存储 undo 日志的地方,是回滚段。

1.4.3 Read View

1.读已提交(PC):在每一次执行快照读时生成ReadView

数据提取过程:

(PS:m_ids:记录哪些事务还没有被提交)

2.可重复读(RR):仅在第一次执行快照读时生成ReadView,后续快照读复用

3.RR级别下使用MVCC能避免幻读吗?

答:能,但不完全能!

解释:连续多次快照读,ReadView会产生复用,没有幻读问题

特例:当两次快照读之间存在当前读,ReadView会重新生成,导致产生幻读

例:

1.5 如何查询一条记录

  1. 获取事务自己的版本号,即 事务ID
  2. 获取 Read View
  3. 查询得到的数据,然后 Read View 中的事务版本号进行比较。
  4. 如果不符合 ReadView 规则, 那么就需要 UndoLog 中历史快照;
  5. 最后返回符合规则的数据

InnoDB 实现多版本控制 (MVCC)是通过 ReadView+ UndoLog 实现的,UndoLog 保存了历史快照,ReadView 规则帮助判断当前版本的数据是否可见。

1.6 redo log日志

为什么要有redo日志?

数据库事务提交后,必须将更新后的数据刷到磁盘上,以保证 ACID 特性。磁盘随机写性能较低,如果每次都刷盘,会极大影响数据库的吞吐量。

优化方式是,将修改行为先写到 redo 日志里(此时变成了顺序写),再定期将数据刷到磁盘上,这样能极大提高性能。

这里的架构设计方法是,随机写优化为顺序写,思路更重要。

假如某一时刻,数据库崩溃,还没来得及刷盘的数据,在数据库重启后,会重做 redo 日志里的内容,以保证已提交事务对数据产生的影响都刷到磁盘上。

一句话,redo 日志用于保障,已提交事务的 ACID 特性。

1.7 总结

  • 常见并发控制保证数据一致性的方法有锁,数据多版本;
  • 普通锁串行,读写锁读读并行,数据多版本读写并行;
  • redo 日志保证已提交事务的 ACID 特性,设计思路是,通过顺序写替代随机写,提高并发;
  • undo 日志用来回滚未提交的事务,它存储在回滚段里;
  • InnoDB 是基于 MVCC 的存储引擎,它利用了存储在回滚段里的 undo 日志,即数据的旧版本,提高并发;
  • InnoDB 之所以并发高,快照读不加锁;
  • InnoDB 所有普通 select 都是快照读;
  • 37
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值