MVCC的作用
MVCC最重要的特点是一致性读不加锁,这样一致性读不会阻塞更新,从而提升了数据库的并发性能。
MVCC的表现形式
历史版本数据的存储
InnoDB多版本数据是通过delete mark的行数据和回滚段中的undo信息组成的。
https://blog.jcole.us/2013/01/10/the-physical-structure-of-records-in-innodb/
历史版本数据的回溯
可见性的判断
Innodb的可见性是通过ReadView实现。
可见规则
如果记录trx_id小于m_up_limit_id或者等于m_creator_trx_id,表明ReadView创建的时候该事务已经提交,记录可见。
如果记录的trx_id大于等于m_low_limit_id,表明事务是在ReadView创建后开启的,其修改,插入的记录不可见。
当trx_id在m_up_limit_id和m_low_limit_id之间的时候,如果id在m_ids数组中,表明ReadView创建时候,事务处于活跃状态,因此记录不可见。
生成时机
RC级别:With READ COMMITTED isolation level, the snapshot is reset to the time of each consistent read operation。
RR级别:With REPEATABLE READ isolation level, the snapshot is based on the time when the first read operation is performed。
注意:单纯的begin和start transaction不会生成,详情下文mysqldump的讲解。
字段含义设计原因
m_ids与m_up_limit_id设计的原因是,事务的提交顺序不是按照事务的初始顺序进行的。
m_low_limit_no 设计目标是兼容这种情况,如果以m_up_limit_id来purge的话,最老的事务开始后提交的事务都无法purge。
- 比如事务1现在是最老的事务。
- 事务100开始时,m_up_limit_id=1,活跃事务2-99。
- 现在有可能2-99已经提交了,所以可以purge,所以使用新的m_low_limit_no表示99。
二级索引的可见性
二级索引记录中没trx_id和roll_ptr字段,如果每次需要回溯到聚簇索引判断可见性,成本就太大了,因此二级索引page中记录了当前page所涉及事务最大的trx->id。判断可见性时,用此page的事务id比较,如果page事务id小于当前view的m_up_limit_id则认为此记录可见,否则需要去cluster index判断。
- 二级索引上的更新操作总是先delete-mark,再insert新记录,真正的delete需要purge去做。
- 需判断二级索引列值和聚集索引列值一致,才能返回聚簇索引上的记录。数据一致才能确保这条二级索引是有效的。
特例:http://mysql.taobao.org/monthly/2018/11/04/
Semi consistent read
Purge
工具对MVCC特性的应用
mysqldump
--single-transaction
Creates a consistent snapshot by dumping all tables in a single transaction. Works ONLY for tables stored in storage engines which support multiversioning (currently only InnoDB does); the dump is NOT guaranteed to be consistent for other storage engines. While a --single-transaction dump is in process, to ensure a valid dump file (correct table contents and binary log position), no other connection should use the following statements: ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not isolated from them. Option automatically turns off --lock-tables.
配合--master-data参数,效果如下图
Tips:
- 先flush tables,再flush tables with read lock,防止flush tables锁太长时间。
- 针--single-transaction的情况在unlock前开启start transaction。
- 单纯的start transsaction不会生成ReadView,需加上/*!40100 WITH CONSISTENT SNAPSHOT */