undo log
回滚段是记录MVCC历史的一个空间,如果开启了独立表空间,会在独立表空间中创建一个回滚表空间,undo表空间有128个段,其中:
1~32段存放于临时表的系统表空间中
33~127段存放于独立undo表空间中
为了事物并发,每个undo段又分为1024个slot
理论上来说,innodb可支持96*1024个事物并发
RR和RC
RR隔离级别(除了Gap锁之外)和RC隔离级别的差别是创建snapshot时机不同。 RR隔离级别是在事务开始时刻,确切地说是第一个读操作创建read view的;RC隔离级别是在语句开始时刻创建read view的。
read view:将当前活跃的事物做一个视图。当在这个事务中要读取该行记录的时候,innodb会将该行当前的版本号与该read view进行比较。
innodb表空间
在理解MVCC如何使用回滚段之前,先了解一下undo段所在的位置。
段–>区–>页–>行
任何情况下,区的大小为1M,在页(16K)装满时,innodb会一次申请4个区
MVCC的undo原理
1、分配回滚段
每当只读事物开始时,会为其分配一个回滚段,如果对临时表产生了写入操作,则会分配到临时表回滚段。如果是普通的只读事物,那么会:
1)采用round-robin的轮询方式来赋予回滚段给事务,如果回滚表空间过大,无法为其分配的时候,purge线程会执行truncate操作。
2)清除操作完成后,选择一个回滚段给事务后,内部会记录一个记录值,表示该事物比上一次清除的值大,是新事物,这样就不会被truncate掉。
3)如果事务在只读阶段使用到临时表,随后转换成读写事务,那么会为该事务分配两个回滚段。
2、使用回滚段
当数据产生变更时,undo日志会记录下变更前的数据以记录历史版本。其中:
insert记录一个undo,delete、update记录一个undo,因此两种操作需要单独分配slot。
具体使用流程:
1)判断当前事物是否使用临时表,如果使用临时表,则为其分配临时表回滚段
2)在临时表操作时不会记录其redo log
3)操作类型为INSERT时,且未分配slot时,为其分配undo slot
4)操作类型为update/delete,且未分配slot时,为其分配undo slot
3、事物Prepare阶段
当事务完成需要提交时,为了和BINLOG做XA,InnoDB的commit被划分成了两个阶段:prepare阶段和commit阶段
为了防止崩溃重启时知道事物的状态,所以设置事物为Prepare
innodb事物在执行sql时,会注册一个XID号,然后存储在事务对象中
4、事务Commit
当事物完成需要提交时,设置事物状态为Commit,先设置insert undo,再设置update
5、事务回滚
如果事物因各种原因需要回滚时,这里就需要借助undo log中的数据来进行恢复
先解析老版本记录,做逆向操作:对于标记删除的记录清理标记删除标记;对于in-place更新,将数据回滚到最老版本;对于插入操作,直接删除聚集索引和二级索引记录。
MVCC
innodb的MVCC是通过每行记录后面三个隐藏列实现。一列记录了事物ID,一列记录了回滚指针,一列记录了行ID。
1)INSERT:插入操作,每次插入时都新生成一个系统版本号,在原来基础上递增
2)DELETE:删除操作,每次删除时都会记录当前版本号,标记为删除版本号
3)UPDATE:实际上包含了两次操作,一次为INSERT操作,插入一行新的记录,生成新的版本号,记录旧ID标记为删除版本号
当在这个事务中要读取该行记录的时候,innodb会将该行当前的版本号与该行记录的read view进行比较。
select语句可见的情况:
版本号<= 当前事务版本号 (记录是在当前事务之前或者由当前事务创建的)
删除版本号 == NULL || 删除版本号 > 当前事务版本号 (记录是在当前事务之后被删除的)