《MySQL》高性能的说法:
为何需要MVCC
对于事务型的存储引擎实现,仅仅依赖锁是不够的,还需要MVCC(Multiversion Concurrency Control )的帮助,可以简单的将MVCC理解成为一个row lock的一个变种,只是在必要的时候加行锁。
InnoDB的MVCC实现方式
每个事物存储引擎的MVCC实现方式是不一样的,InnoDB的MVCC简单来讲是通过给表添加两列隐藏列。
一列(创建列)存储行的insert(如果行不存在)时间或者update(如果行已存在)时间,一列存储行的删除时间,当然,这里的时间并非我们所说的时分秒,而是系统版本号(system version number),列存储的SVN是事物开始时刻的SVN,每开始一个新的事物,SVN号递增。
MVCC只有在隔离级别是READ COMMITED(Oracle默认)和REPEATABLE READ(MySQL默认)两个隔离级别下工作。
现在讨论在REPEATABLE READ下的MVCC实现:
SELECT
a. Innodb查找SVN小于等于当前事物的SVN的行,如果是小于,说明行之前就已经存在,如果是等于,说明这行是事物本身修改过的.
b.行的删除时间列要么为空(说明该行未被删除)要么删除时间列的SVN大于当前事物的SVN(表示行是在事物开始之后被删除的).
只有记录满足以上两条,才会被select语句返回!
Insert
插入之后以当前事物的SVN号更新创建列
Delete
删除之后,用当前SVN更新删除列
Update
更新创建列为当前SVN,同时更新删除列为update之前的创建列的SVN值
这样设计的优点是大部分的读操作都不用加锁了,使数据库操作简单,性能好,不足之处是增加了存储开销,需要额外的维护工作
查阅5.5的官方文档,关于MVCC的介绍是这样的:
InnoDB的MVCC是通过保存旧版本的修改信息来实现事物的并发控制和回滚。这些信息以一种数据结构的形式保存在表空间中,这种数据结构就是“rollback segment”回滚段可以提供两项功能:回滚,一致性读。
与MVCC相关的元素
DB_TRX_ID:占6字节,用来标识最近一次修改(insert|update)行的事物的标识符,至于delete操作,在innodb看来也不过是一次update操作,更新行中的一个特殊位将行表示为deleted。并非真正删除。
DB_ROLL_PTR:占用7个字节,滚动指针指向回滚段中的对应回滚日志记录,如何update一行,那么改行旧的信息就会被保存到指针所指向的回滚段中。
DB_ROW_ID:该值随行数的增多而增加,如果是cluster index,会包含这列,其他索引则不会有这列。
对于回滚段的管理:
Insert Logs:当事物被提交时,所保存的insert 回滚记录就可以被删除
Update Logs:这个日志不仅仅在rollback时需要,在一致性读也需要,所以不能随便删除,只有当数据库所使用的快照中不涉及该日志记录,对应的回滚日志才可以删除。
回滚段的管理指导:
经常将一些事务提交,包括哪些只发出一致性读的事务,否则InnoDB无法删除回滚段中的 undo update logs,这将导致回滚段增长过快直到填满表空间。
在InnoDB中,发出Delete语句之后,改行并不会立刻被物理的从数据库中删除,只有当对应的行update undo logs被删除之后,才会被物理的删除(purge)purge操作很快,时间等于delete所用时间。
有个问题:在频繁的进行小规模的插入和删除操作,purge线程将会滞后。因为无法删除这些被标记为deleted的行,这会导致表越来越大,导致磁盘瓶颈,性能下降。
解决办法:限制新行的操作,分配更多的资源给purge线程。涉及参数innodb_max_purge_lag
当purge_lags表示有多少经过delete或者update操作被标记为deleted的行,没有被purge,如果该值超过了innodb_max_purge_lag值,则delete和insert,update操作将会被挂起。
The InnoDB
transaction system maintains a list of transactions that have index records delete-marked by UPDATE
or DELETE
operations. The length of this list represents the purge_lag
value. When purge_lag
exceedsinnodb_max_purge_lag
, each INSERT
, UPDATE
, and DELETE
operation is delayed by ((purge_lag
/innodb_max_purge_lag
)×10)–5 milliseconds. The delay is computed in the beginning of a purge batch, every ten seconds. The operations are not delayed if purge cannot run because of an old consistent readview that could see the rows to be purged.
root@localhost>show engine innodb status\G
------------
TRANSACTIONS
------------
Trx id counter 9652
Purge done for trx's n:o < 7965 undo n:o < 0 state: running but idle
History list length 17
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 13, OS thread handle 0x8effdb70, query id 361 localhost root init
show engine innodb status
来源:oschina
链接:https://my.oschina.net/u/1440383/blog/198353