Mysql 锁机制(自制图)
Mysql 如何做到读写并行?<br>(多版本控制)
MVCC
简单来说就是通过维护数据历史版本,从而解决并发访问情况下的读一致性问题。
Mysql 中的死锁
Mysql 针对死锁的两种处理策略(喜马拉雅)
二,<b><font color="#f15a23">发起死锁检测</font></b>,主动回滚某一条事务,默认是开启的
缺点:
死锁检测会造成大量CPU消耗。
每当一个事务被锁的时候,就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,也就是死锁
如何解决死锁
可以从业务逻辑上考虑
共享资源拆分为许多个小的共享资源
比如,把要更新的数据放在多条记录上,比如:把余额账户分成多个子账户
Mysql 中的锁
InnoDB 实现了两种类型的<b><font color="#f15a23">行级锁</font></b>
共享锁 (S锁)
排他锁(X锁)
--------------
行级锁优缺点
优点
锁的粒度小,发生锁冲突的概率低;处理并发的能力强
加锁方式:
自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁。
为实现多粒度的锁机制,InnoDB 还有两种表级别的锁
意向共享锁 (IS)
事务给数据行添加 S 锁前必须获得该表的 IS 锁
意向排它锁 (IX)
事务给数据航添加 X 锁前必须获得该表的 IX 锁
行锁的分为三种算法
行级锁
InnoDB 是针对索引加锁的,不是针对记录加锁。
<b><font color="#c41230">InnoDB 使用三种行锁算法支持事务隔离级别</font></b>
Record Locks
该锁为索引记录上的锁,使用索引锁定记录
Gap Locks
该锁会锁定一个范围,但不包括记录本身。
Next-key Locks
该锁是 Record Locks 和 Gap Locks 的组合,即锁定一个范围并且锁定该记录本身。
<b><font color="#f15a23">InnoDB 使用 Next-key Locks 解决幻读问题。</font></b>
锁优化建议:
1,设计合理的索引
2,减少范围过滤条件
3,缩短事务执行时间
4,尽可能使用低级别的事务隔离
Mysql 隔离级别
<b><font color="#f15a23">四个隔离级别</font></b>
1.,读未提交(Read UnCommitted)
一个事务读取到另一个事务未提交的数据。(脏读)
大部分业务场景下都不不允许脏读出现。
2,读已提交(Read Committed)
事务A读取事务B中修改的数据,在事务B提交前和提交后读取到的数据不一致的现象。(不可重复度)
一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果。
3,可重复读(Repeatable Read)<br>Mysql 默认隔离级别
比如:一个事物中,多次对整表进行统计查询,结果不一致。(幻读)
按照可重复读的定义,一个事务启动的时候,能够看到所有已经提交的事务结果
通过<b><font color="#f15a23">快照读</font></b>
通过 redo log 版本链实现:
因此,一个事务只需要在启动的时候声明说,“以我启动的时刻为准,如果一个数据版本是在我启动之前生成的,就认;<br>如果是我启动以后才生成的,我就不认,我<b><font color="#f15a23">必须要找到它的上一个版本</font></b>”。
<b><font color="#f1753f">可重复读和读已提交的区别:</font></b>
1、在可重复读级别下,在<b><font color="#f15a23">事务开始</font></b>的时候会创建一个readview<br><br> 2、在读提交级别下,每个<b><font color="#f15a23">语句执行前</font></b>都会重新生成一个新的readview
在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;
对于可重复读,查询只承认在事务启动前就已经提交完成的数据;<br><br>对于读提交,查询只承认在语句启动前就已经提交完成的数据;
4,序列化(Serizlizable)
所有事务都串行执行(可以避免脏读,不可重复读,幻读)
Buffer Pool(自制图)
什么是buffer pool?
Buffer Pool 的功能就是缓存 “页”,减少磁盘IO,提高读写效率。<br>
Buffer Pool 的内存结构?
查询
先在Buffer Pool 中查询需要的数据页是否存在,存在就返回,不存在就从磁盘查询,加载到Buffer Pool 中。
<b><font color="#f15a23">更新</font></b>
update school set name = 'xs' where id = 400;<br><br>1. 先查询要更新的数据页是否在Buffer Pool 中,有就直接更新。不存在从磁盘读取到 Buffer Pool 中,再更新。<br>2. 将更新内容写入redo log(崩溃恢复)。<br>
这种先更新 Buffer Pool 中数据页的值,在合适的时机再刷回磁盘的方法,大大提高了效率,但也带来了“脏页”的问题。
<b><font color="#f15a23">“脏页” 何时写回磁盘</font></b>
1. 后台线程定时刷新
2. Buffer Pool 内存不足
3. redo log 写满
4. 数据库正常关闭时
Explain 使用
expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra,
id
select_type
table
<b><font color="#f15a23">type</font></b>
type 字段比较重要, 它提供了判断查询是否高效的重要依据依据. 通过 type 字段, 我们判断此次查询是 全表扫描 还是 索引扫描 等.
ALL: 全表扫描
Index: 全索引扫描
eq_ref: 唯一索引扫描
ref: 通常指的是像前缀扫描这些
system,const: 常量级别
NULL: 效率最高,执行时不扫描全表或者索引, 例如通过索引获取最小值
possible_keys
<b><font color="#f15a23">key</font></b>
key列显示MySQL实际决定使用的键(索引
ken_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)<br><br>不损失精确性的情况下,长度越短越好
ref
rows
估算找到符合条件的记录所扫描的行数, 通常来说,越小越好
Extra
包含MySQL解决查询的详细信息,
Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤<br><br>Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询<br><br><b><font color="#f15a23">Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”</font></b><br><br>Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。<br><br>Impossible where:这个值强调了where语句会导致没有符合条件的行。<br><br>Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行