MySQL性能优化专栏

1.MySQL性能优化1-MySQL底层索引结构
2.MySQL2-Explain详解
3.MySQL3-索引最佳实战
4.MySQL4-MySQL内部组件结构
5.MySQL5-事务隔离级别和锁机制
6.MySQL6-深入理解MVCC和BufferPool缓存机制

MVCC多版本并发控制机制

MySQL在可重复读隔离级别下如何保证事务较高的隔离性,也就是同样的SQL查询语句在一个事务里多次执行查询结果相同,就算其他事务对数据有修改也不会影响当前事务SQL语句的查询结果。
这个隔离性就是靠MVCC(Multi Version ConCurrent Control)机制来保证的,对一行数据的读和写两个操作默认不会通过加锁互斥来保证隔离性,避免了频繁枷锁互斥,而在串行化隔离级别为了保证较高的隔离性是通过将所有操作加锁互斥来实现的。
MySQL在读已提交和可重复读隔离级别下都实现了MVCC机制。

undo日志版本链与read view机制详解

undo日志版本链是指一行数据被多个事务依次修改过后,在每个事务修改完成后,MySQL会保留修改前的数据。并且会用两个隐藏字段trx_id和rolle_pointer把这些undo日志串联起来形成一个历史记录版本链
MySQL6-深入理解MVCC和BufferPool缓存机制-LMLPHP
在可重复读隔离级别,当事务开启执行任何查询SQL时会生产当前事务的一致性视图read-view,该视图在事务结束之前都不会有变化(读已提交如果是隔离级别在每次执行查询SQL时都会重新生成),这个视图由执行查询时所有未提交事务id数组(数组里最小的id为min_id)和已创建的最大事务(max_id)组成,事务里的任何SQL查询结果需要从对应的版本链里的最新数据开始逐条跟read-view做对比从而得到最终的快照结果。

版本链比对规则

  1. 如果row的trx_id落在绿色部分(trx_id<min_id)表示这个版本是已提交的事务生成的,这个数据是可见的
  2. 如果row的trx_id落在红色部分(trx_id>max_id)表示这个版本是由将来启动的事务生成的,是不可见的(若row的trx_id就是当前自己的事务是可见的)
  3. 如果row的trx_id落在黄色部分(min_id <= trx_id <= max_id),那就包括两种情况
    a. 若row的trx_id在视图数组中,表示这个版本是由还没提交的事务生成的,不可见(若row的trx_id是当前自己的事务是可见的)
    b. 若row的trx_id不在视图数组中,表示这个版本是已经提交了的事务生成的,可见。

对于删除的情况可以认为是update的特殊情况,会将版本链上最新的数据复制一份,然后将trx_id修改成删除操作的trx_id,同时在该条记录的头信息(record header)里的(deleted_flag)标记位写上true来表示当前记录已经被删除,在查询时按照上面的规则查到对应的记录如果delete_flag标记位为true,意味着记录已被删除,则不返回数据。

注意:begin/start transaction命令并不是一个事务的起点,在执行到她们之后的第一个修改操作innoDB表的语句,事务才真正启动,才会向MySQL申请事务id,MySQL内部是严格按照事务的启动顺序来分配事务id的。

总结

MVCC机制的实现就是通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取同一条数据在版本链上的不同版本数据。
面试的时候可以这么讲:MVCC机制就是通过undo版本链和read-view机制来实现的,它会在每个事务执行查询SQL的时候生成一个readView,然后通过它跟版本链对比来实现隔离性的。undo版本链就是把每个操作都记录下来,然后分配一个事务id和指针,指向之前数据的地址。read-view就是根据未提交事务的事务id数组和已提交事务的最大id生成的。然后把他们分成三个区间拿row的trx_id做对比

InnoDB引擎SQL执行的BufferPool缓存机制

其实我们做的增删改查都是在BufferPool机制执行的
MySQL6-深入理解MVCC和BufferPool缓存机制-LMLPHP

执行过程

示例语句:

  1. 加载缓存数据:加载id为1的记录所在整页数据
  2. 写入更新之前的数据到undo文件里
  3. 更新buffer_pool内存中的数据
  4. 写入redo日志(内存中)
  5. 准备提交事务,redo日志写入磁盘
  6. 准备提交事务,写入binlog日志写入磁盘
  7. 写入commit标记到redo日志文件里,提交事务完成,该标记为了保证事务提交后redo与binlog数据一致
  8. 随机写入磁盘,以page为单位写入,这步做完磁盘的数据才会更新

undo日志和rebo日志和binlog日志的区别?

undo日志是用来给MVCC机制使用,InnoDB引擎特有,在引擎层。如果事务失败,可以利用undo日志回滚buffer_pool数据。
rebo日志是用来回滚整个buffer_pool内存的值,如果MySQL突然挂掉可以用rebo日志重写。InnoDB引擎特有,在引擎层。
binlog日志是用来恢复磁盘上的数据,在server层,每个引擎都会有。

为什么MySQL不能直接更新磁盘上的数据而且设置这么一套复杂的机制来执行SQL?

因为来一个请求就直接对磁盘文件进行随机读写,然后更新磁盘文件里的数据,性能可能相当差。
因为磁盘随机读写的性能是非常差的,所以直接更新磁盘文件是不能让数据库抗住很高并发的。
MySQL这套机制看起来复杂,但是它可以保证每个更新请求都是更新内存BufferPool,然后顺序写日志文件,同时还能保证各种异常情况下的数据一致性。
更新内存的性能是极高的,然后顺序写磁盘上的日志文件性能也是非常高的,要远高于随机读写磁盘文件。正是通过这套机制,才能让我们的MySQL数据库在较高配置的机器上每秒可以抗下几千的读写请求。

06-02 21:18