最近尝试坚持更文,先扒拉一下比较经典的因为作品和技术贴,学习一下技术分享的方式。今天是上个月看过的一篇mysql多版本并发控制MVCC机制的知识。(图片补充中)
1 MVCC的定义
MVCC全称Multi Version Concurreny Control,多版本并发控制,也可称之为一致性非锁定读;它通过行的多版本控制方式来读取当前执行时间数据库中的行数据。实际上使用的快照数据,这样就可以实现不加锁读。MVCC主要应用于Read Commited和Repeatable read两个事务隔离及级别。
举个例子,程序员A正在读取数据库中某些内容,而程序员B正在给这些内容做修改(假设是在一个事务内修改,大概持续10s左右),A在这10s内则可能看到一个不一致的数据,在B没有提交前,如何让A能够一直读到的数据都是一致的呢?
有几种处理方法,第一种:基于锁的并发控制,程序员B开始修改数据时,给这些数据加上锁,程序员A这时再读就发现读取不了,处于等待情况,只能等B操作完菜心读数据,这保证A不会读到一个不一致的数据,但是这个会影响程序的运行效率。还有一种情况就是:MVCC,每个用户连接数据库时,看到的是某一特定时刻的数据库快照,不会读到B事务中的数据修改情况,知道B事务提交,才会读取B的修改内容。
一个支持MVCC的数据库,在更新某些数据时,并非使用新数据覆盖旧数据,而是标记旧数据是过时的,同时在其他地覅新增一个数据版本。因此,同一份数据有多个版本存储,但只有一个是最新的。
MVCC有两种实现方式,第一种实现方式是将数据记录的多个版本保存在数据库中,当这些不同版本数据不再需要时,垃圾收集器回收这些记录。这个方式被PostgreSQL和Firebird/Interbase采用,SQL Server使用类似机制,所不同的是旧版本数据不是保存在数据库中,而保存在不同于主数据库的另外一个数据库tempdb中。第二种实现方式只在数据库保存最新版本的数据,但是会使用undo时动态重构旧版本数据,这种方式被Oracle和Mysql/InnoDB使用。
2 InnoDB的逻辑存储结构
InnoDB的数据保存在表空间中,表空间又包含各种段,其中有数据段,索引段,回滚段。InnoDB中数据以B+Tree的数据结构存储的,非叶子节点即是索引,叶子节点即是数据行,回滚用于存储undoLog,undoLog中记录的就是多版本数据,用于快照读和事务失败后的数据回滚, Mysql在合适的时机会清理undoLog。VCC的实现依赖于每行的隐藏字段,DB_TRX_ID, DB_ROLL_PTR,删除标记位,还有read_view.
3 InnoDB的MVCC实现机制
MVCC可以认为是行级锁的一个变种,它可以在很多情况下避免加锁操作,因此开销更低。MVCC的实现都实现了非阻塞的读操作,写操作也只锁定必要的行。InnoDB的MVCC实现是通过保存数据在某个时间点的快照来实现的。一个事务,不管其执行多长时间,其内部看到的数据是一致的。也就是事务在执行的过程中不会相互影响。下面我们简述一下MVCC在InnoDB中的实现。
InnoDB的MVCC,通过在每行记录后面保存两个隐藏的列来实现:一个保存了行的创建时间,一个保存行的过期时间(删除时间),当然,这里的时间并不是时间戳,而是系统版本号,每开始一个新的事务,系统版本号就会递增。在RR隔离级别下,MVCC的操作如下:
1.select操作
InnoDB只查找版本早于(包含等于)当前事务版本的数据行。可以确保事务读取的行,要么是事务开始前就已存在,或者事务自身插入如或修改的记录。行的删除版本要么未定义,要么大于当前事务版本号。可以确保事务读取的行,在事务开始之前未删除。
2.insert操作。将新插入的行保存当前版本号为行版本号。
3.delete操作。将删除的行保存当前版本号为删除标识。
4.update操作。变为insert和delete操作的组合,insert的行保存当前版本号为行版本号,delete则保存当前版本号到原来的行作为删除标识。
由于旧数据并不真正的删除,所以必须对这些数据进行清理,InnoDB会开启一个后台线程执行清理工作,具体的规则是将删除版本号小于当前系统版本的行删除,这个过程叫做purge。