InnoDB MVCC浅谈
作者:周琳
//转载请标注出出处
1.行记录隐藏列的意义 可以从row_search_for_mysql(storage/innobase/row/row0sel.cc, line 3661)函数开始,这个函数是mysql服务器层面搜索记录的函数,该函数有一个重要的参数就是row_prebuilt_t* prebuilt,该参数是包含了查询的记录的信息。进行Debug调试可以发现内存中一行记录包含了如下的几个隐藏列: 测试的客户端:
测试实例中,test1表只有id为int的一列。
从gdb信息中可以发现,内存中的一行记录有三个隐藏列分别为:DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR。除过DB_ROW_ID以外,DB_TRX_ID和DB_ROLL_PTR分别代表了每行记录的事务ID和每行记录的回滚指针。InnoDB中有运行期间有一个全局的事务链表,每个事务的开始都会把事务ID放到链表中。DB_ROLL_PTR指针用于指向undo 记录,构造多版本的。
2.InnoDB多版本控制
InnoDB对于每一行记录都维护了2个隐藏列,其中一列存储行辈修改的”时间”,另外一列存储辈删除的”时间”,注意,InnoDB存储的并不是实际的时间哦,而是对应的系统版本号,所以版本号可以作为事务号。对于每一行查询语句,InnoDB都会把这个查询语句的版本号同这个查询语句遇到的行记录的版本号进行比对,然后结合不同的事务隔离界别来选择是否返回该行记录。针对mysql的常见操作进行说明下:
(1) select操作:
对于select的操作,只有同时满足如下2个条件才返回行记录
a) 行的修改版本号小于等于该事务版本号
b) 行的删除版本号要么没有被定义,要么大于事务版本号。
如果行的修改或者删除版本号大于事务号,说明行是被修改事务后启动的事务修改或者删除的。在可重复读的隔离级别下,后开始的事务堆数据的影响不应该被先开始的事务看见,所以应该忽略后开始的事务的更新或者删除操作。
(2) insert操作:
新插入的行,行的修改版本号为更新为该事务的事务号。
(3) update操作:
更新行的时候,InnoDB会把原来行复制一份,并把当前的事务号作为改行的修改版本号。
(4) delete操作:
对于删除,InnoDB直接把改行的删除版本号修改为当前事务号,相当于标记为删除,而不是物理的删除。真是的删除是在InnoDB的purge线程去做的。
3.MVCC实现原理图
Innodb启动后会初始化一个全局的事务最系统,事务系统中保存了innodb运行期间事务的所有信息。每当一个线程start或者begin一个事务后,会有一个trx_t的结构作为事务处理的句柄,依据事务ID的大小的不同,去获取read_view_t中对应记录。在read_view_t中有保存了undo的回滚相关信息,MVCC的基本信息依据每个记录的事务ID、回滚指针,去undo链表中查找对应的之前的多版本的数据返回给客户端。这里仅仅是做了个简单的介绍。