为了提高并发MySQL加入了多版本并发控制,它把旧版本记录保存在了共享表空间(undolog),当事务提交之后将重做日志写入磁盘(前提innodb_flush_log_at_trx_commit为1)清空undolog,在5.6版本之后unodlog可以独立出共享表空间,引入MVCC的目的就是减少锁的挣用,通过阅读高性能mysql这本书的解释是MVCC是行级锁的一个变种,使大多数的读操作可以不用加锁,写操作也只锁定必要的行。。
正文
多版本并发控制只针对innodb的repeatable read和read committed这两种隔离级别。多版本并发控制的原理就是在每个记录行后面增加两个标示列用来存储该行的状态,分别存储改行的新系统版本号和删除系统版本号。系统的版本号会随着每增加一个事务递增。
TABLE
ID | NAME | Trx_id | De_Trx_id |
1 | a | 1 |
|
有四个事务:select(trx=2),insert(trx=3),delete(trx=4),update(trx=5)
现在这四个事务同时对该行进行操作,演示SELECT的可重复读,假设四个操作在SLECT提交之前都未提交,当然SELECT是能查看到四个操作的记录的。
SELECT:
SELET会根据以下两个条件去查找记录,下面两个条件需要同时满足:
1.只查找行的系统版本号小于或等于当前事务版本号的记录行。
2.删除版本号为空或者大于当前事务版本号的记录行。
BEGIN TRANSELECT NAME FROM TABLE WHERE ID=1
ID | NAME | Trx_id | De_Trx_id |
1 | a | 1 |
|
WAIT 10 MINUTESELECT NAME FROM TABLE WHERE ID=1
COMMIT
ID | NAME | Trx_id | De_Trx_id |
1 | a | 1 | 4 |
根据SELECT 的查找条件INSERT记录的事务版本号大于当前版本号所以不会被查到;DELETE的事务删除版本号大于当前版本号,所以该行会被查出;UPDATE第一行的事务的版本号小于当前版本号而删除版本号大于当前版本号,可以被查到,第二行因为事务版本号大于当前版本号所以不满足,最终SELECT查询的记录是UPDATE操作的第一条记录;SELECT两次查询的结果一致,满足可重复读隔离级别。当然在这里除了INSERT操作,其它的操作都无法在SELECT提交之前提交。
INSERT:
INSERT INTO TABLE(ID,NAME) VALUES(2,'B');
ID | NAME | Trx_id | De_Trx_id |
2 | b | 2 |
|
DELETE:
DELETE FROM TABLE WHERE ID=1;
ID | NAME | Trx_id | De_Trx_id |
1 | a | 1 | 3 |
UPDATE:
BEGIN TRANUPDATE TABLESET NAME='B'WHERE ID=1COMMIT
ID | NAME | Trx_id | De_Trx_id |
1 | a | 1 | 4 |
ID | NAME | Trx_id | De_Trx_id |
1 | b | 4 |
|
注意:多版本并发控制不支持myisam存储引擎。
在缓存中有一个用于维护锁的资源,对锁的维持需要消耗mysql的资源,多版本并发控制它就是减少了用于维持锁资源的消耗来提高性能,所以日志的写操作都是先undo再redo。
备注: 作者:pursuer.chen 博客:http://www.cnblogs.com/chenmh 本站点所有随笔都是原创,欢迎大家转载;但转载时必须注明文章来源,且在文章开头明显处给明链接。 《欢迎交流讨论》 |