MySQL要点总结二
大纲
一.InnoDB的内存结构和更新机制
二.InnoDB的存储模型
三.并发事务原理
四.索引原理和索引优化
三.并发事务原理
1.并发执行多个MySQL事务可能遇到的问题
2.多个事务并发更新或查询时可能出现的问题
3.SQL标准中对事务的4个隔离级别
4.uodo log多版本链介绍
5.基于undo log多版本链实现ReadView机制
6.RC隔离级别如何基于ReadView机制实现
7.RR隔离级别如何基于ReadView机制实现
8.多事务并发运行的隔离机制总结
9.多事务更新同一行数据如何加锁避免脏写
10.数据库出现不确定的性能抖动的原因
11.如何优化数据库不确定性的性能抖动
1.并发执行多个MySQL事务可能遇到的问题
问题一:多个事务并发执行时,可能会同时对缓存页里的同一行数据进行更新。这里并发更新同一行数据的冲突如何处理,是否通过加锁进行处理。
问题二:多个事务并发执行时,可能有的事务在进行更新,有的事务在进行查询。这里并发更新和查询同一行数据的冲突应该如何处理。
要解决这些问题,就涉及同时写和同时读写的并发冲突处理机制。其中就包括了MySQL事务的隔离级别、MVCC多版本隔离、锁机制等。
2.多个事务并发更新或查询时可能出现的问题
(1)脏写
脏写的定义就是事务B修改还没提交的事务A修改过的数据。因为事务A随时会回滚,所以会导致事务B修改的值也没了。
(2)脏读
脏读的定义就是事务B查询还没提交的事务A修改过的数据。因为事务A随时会回滚,可能导致事务B再次查询就读不到之前的数据。也就是导致事务B在前后时间点查询同一行数据时出现脏读。
(3)不可重复读(不可重复读到同一个值)
所谓不可重复读,就是事务A多次查询一条数据,每次读到的值不一样。这个过程中可能别的事务会修改这条数据,且修改后这些事务也提交了。在避免脏读的前提下,也导致事务A每次查询到的值都不一样。
所谓脏写,就是事务A和B没提交的情况下,都修改同一条数据。结果其中事务A回滚了,把另外一个事务B修改的值也给撤销了。所以脏写就是事务A和事务B在没提交的情况下修改同一个值。
所谓脏读,就是事务A修改了一条数据的值,结果还没提交。另外一个事务B就读到了事务A修改的值,然后事务A却又回滚了。那么事务B再次读该数据时就读不到刚才读到那个要修改的值了。所以脏读就是事务B读到了事务A修改某条数据后还没提交的值。
(4)幻读
所谓幻读,指的是一个事务用一样的SQL多次查询一批数据,结果每次查询都会发现查到了一些之前没看到过的数据。
3.SQL标准中对事务的4个隔离级别
SQL标准的事务隔离级别,并不是MySQL的事务隔离级别。MySQL在具体实现事务隔离级别时会有点差别。SQL标准规定了4种事务隔离级别。规定多个事务并发运行时互相是如何隔离的,从而避免事务并发问题。
这4中级别包括:Read Uncommitted(读未提交)、Read Committed(读已提交)、Repeatable Read(可重复读)、Serializable(串行化)。不同的隔离级别可以避免不同的事务并发问题。
(1)Read Uncommitted隔离级别—读未提交
不允许发生脏写,可以去读一些事务里未提交的数据。这种隔离级别下,两个事务不能改未提交。但是可能发生脏读、不可重复读、幻读。一般来说,不会把事务隔离级别设置为读未提交。
(2)Read Committed隔离级别—读已提交
不会发生脏写和脏读,只能读事务中已提交的数据。这种隔离级别下,是无法读取事务在没提交情况下修改的值。但是可能发生不可重复读、幻读,该隔离级别的简称是RC。把事务隔离级别设置成RC指的就是设置读已提交级别。
(3)Repeatable Read隔离级别—可重复读
对同一行数据,在事务中随时可重复读出同样的值。这种隔离级别下,不会发生脏写、脏读和不可重复读,但可能发生幻读。该隔离级别简称RR,把事务隔离级别设置成RR指的是设置可重复读。RR隔离级别,只保证对同一行数据的多次查询不会被读到不一样的值。
(4)Serializable隔离级别—串行化执行
不允许多个事务并发执行。这种隔离级别下,多个事务只能串行起来执行。所以不会出现脏写、脏读、不可重复读、幻读的问题。一般来说,也不会把事务隔离级别设置为串行化级别。
(5)MySQL是如何支持4种事务隔离级别的
SQL标准下的4种事务隔离级别,平时用的比较多的是RC和RR两种级别。在MySQL中也支持这4中事务隔离级别。MySQL默认的事务隔离级别是RR级别,且MySQL的RR级别可避免幻读。SQL标准里的RR级别是会发生幻读的,但MySQL的RR级别避免了幻读。所以MySQL事务默认不会发生脏写、脏读、不可重复读和幻读的问题。
MySQL事务的执行都是并行的,各个事务互相不影响。事务A执行中出现事务B,事务A不会读到事务B未提交的修改值。即使事务B提交了修改值事务A也不会读到。即使事务B提交了插入的一行值事务A也依然不会读到。
MySQL为了实现这种事务之间互不影响的效果,使用的是MVCC机制—多版本并发控制隔离机制。依托MVCC机制,MySQL就可以让RR级别避免不可重复读和幻读的问题。MySQL的默认事务隔离级别是RR,一般不需修改。
4.uodo log多版本链介绍
MySQL默认的RR隔离级别,不会出现脏写、脏读、不可重复读、幻读。每个事务执行时,跟别的事务是没有关系的。不管别的事务怎么更新和插入,查到的值都是不变、都是一致的。而这就是由经典的MVCC多版本并发控制机制实现的。
MySQL每条数据都有两个隐藏字段:一个是trx_id,一个是roll_pointer。trx_id就是最近一次更新这条数据的事务id。roll_pointer就是指向更新这个事务之前生成的undo log。
多个事务串行执行时:每个事务的修改,都会更新隐藏字段trx_id和roll_pointer。同时多个数据快照对应的undo log,会通过roll_pointer指针串联起来,从而形成一个重要的undo log版本链。
5.基于undo log多版本链实现ReadView机制
(1)ReadView的关键内容
MySQL执行一个事务时会生成一个ReadView,里面关键的内容有4个:
一.m_ids,表示此时的活跃事务
二.min_trx_id,表示m_ids里最小的值
三.max_trx_id,表示此时的最大事务ID
四.creator_trx_id,表示当前这个事务自己的id
(2)基于undo log多版本链实现ReadView机制
通过undo log多版本链条,加上事务开启时创建的一个ReadView。当有查询时,事务就能根据ReadVIew机制判断应读取哪个版本的数据,这个ReadVIew机制可以确保一个事务只能读到:它自己开启前其他事务进行更新并已经提交的值,以及它自己更新的值。
假如事务开启前,有其他的事务已经正在运行,那么当事务开启后,其他事务更新了值并已提交,这时该事务读取不到那些事务更新的值。
假如事务开启后,才有其他事务开启并更新了值以及进行了提交,那么这时该事务也是读取不到那些事务更新的值。
通过这个ReadView机制就可以实现多个事务并发执行时的数据隔离。
6.RC隔离级别如何基于ReadView机制实现
(1)RC隔离级别与ReadView机制
一.RC隔离级别就是读已提交的隔离级别
指的是一个事务在运行期间,只要别的事务修改数据并且提交了。那么这个事务就可以读取到别的事务修改的数据,所以RC隔离是会发生不可重复读、幻读的问题。
二.ReadView机制是基于undo log版本链条实现的一套读视图机制
指的是事务开启时生成一个ReadVIew:如果值是事务本身更新的,是可以读取到的。如果值是在事务生成ReadView之前提交的事务修改的,也可以读取。如果值是生成ReadView后再开启事务修改并提交的,则是读取不到的。
三.基于ReadView机制来实现RC隔离级别的核心
设置RC隔离级别的一个事务,每次发起查询都重新生成一个ReadView。
(2)基于ReadView机制实现RC隔离级别
实现RC隔离级别的关键点在于事务每次查询时都生成新的ReadView。如果一个事务在这次查询之前,有其他事务修改了数据而且还提交了。那么其生成ReadView的m_ids列表,当然就不包含这个已提交的事务。既然不包含已提交的事务,那么就可以读取到已提交事务修改过的值,这就是基于ReadView实现的RC隔离级别的原理。
7.RR隔离级别如何基于ReadView机制实现
(1)MySQL的RR隔离级别避免不可重复读 + 幻读
MySQL的RR级别下,一个事务读一条数据,无论读多少次都是一个值。其他事务修改数据后哪怕提交了,该事务也无法看到其他事务修改的值。同时如果其他事务插入了一些新的数据,该事务也是读取不到。这样就分别避免了出现不可重复读的问题,以及避免了出现幻读的问题。
<