InnoDB的MVCC机制
MVCC全称为:Multiple Version Concurrency Control,即多版本并发控制。这是一种既保证数据一致性,又保证高并发性能的机制。即一行数据可能存在多个版本,每个事务看见的版本不一样。 MVCC在InnoDB中是通过隐藏列和Undo日志来实现的。
隐藏列
对于数据库中的每一行数据,其实除了我们可以看见的列以外,还有另外三个列:DB_TRX_ID
、DB_ROLL_PTR
、DB_ROW_ID
。
- DBTRXID:最后一个插入或者更新该记录的事务id,删除会当成更新来处理,同时在该行数据的头部标记一下
- DBROLLPTR:指向undo log里的一条记录,通过undo log中的记录链,可以恢复出该记录之前版本的数据。
- DBROWID:对于InnoDB自动创建的主见索引时,该项有值,其他情况没有
undo log
undo log分为insert undo log和update undo log。undo log存储在共享表空间的rollback segment中。其存储的是一行数据的一个副本。 insert的undo log在事务提交后,直接删除,因为该记录只有这个记录可见, update的undo log在事务提交后,会有专门的purge thread去处理,因为,可能多个事务需要用到该日志来构建之前的数据。
DBROLLPTR指向的是undo log的地址,如果有多个版本的话,通过这个指针可以找到之前的版本。
MVCC的实现
为了实现一致性的读,InnoDB在每次读取操作时,会建立一个叫做read view
的对象,里面包含三个值:up_limit_id
low_limit_id
trx_ids
.
- uplimitid: 当前活跃的事务中未提交的最小事务id
- lowlimitid: 当前活跃的事务中未提交的最大事务id + 1
- trx_ids: 活跃的事务id列表
当一个事务读取数据时,对于每一行数据,通过其DBTRXID和uplimitid、lowlimitid进行判断,
- < uplimitid: 证明该条记录在当前事务开始之前就已经存在,并没有修改过,所以是对当前事务可见的;
- > lowlimitid: 证明是当前事务创建后才的某个事务提交或者修改的数据,对当前事务肯定不可见。对于在之间的事务id;
- btween 则遍历trxids列表,如果在trxids中,则表示创建read view之后提交的,不可见,如果不在,则可见。
注意,对于RR和RC生成read view的时机是不同的:
- RR: 在事务开启后的第一条查询语句时,生成,以后都用这个
- RC: 事务中的每个查询语句,都会生成新的read view.
快照读/锁定读
一般的SELECT操作都是快照读,即读取的是数据的一个版本。锁定读,则是通过下面的几个语句实现:
- select … lock in share mode
- select … for update
- insert
- update
- delete