幻读
幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。
session B的修改结果,被session A之后的select语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。
产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。
因此,为了解决幻读问题,InnoDB只好引入新的锁,也就是间隙锁(Gap Lock)。
Gap Lock
间隙锁,锁的就是两个值之间的空隙。数据行是可以加上锁的实体,数据行之间的间隙,也是可以加上锁的实体。 跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。间隙锁之间都不存在冲突关系。
间隙锁和行锁合称next-key lock,每个next-key lock是前开后闭区间。
间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的
间隙锁是在可重复读隔离级别下才会生效的。
RC级别中有可能出现的数据和日志不一致问题,需要把binlog格式设置为row。
(statement 记录逻辑是按照commit提交的顺序,row 记录方式是每行数据的变动情况。但是修改表和列等情况会产生很大体量的日志)
案例:
SELECT * FROM t where c>=15 and c<=20 for update; 会加如下锁: next-key lock:(10, 15], (15, 20] gap lock:(20, 25)
SELECT * FROM t where c>=15 and c<=20 order by c desc for update; 会加如下锁: next-key lock:(5, 10], (10, 15], (15, 20] gap lock:(20, 25)
(21讲)
加锁规则
两个“原则”、两个“优化”和一个“bug”
原则
- 加锁的基本单位是next-key lock。希望你还记得,next-key lock是前开后闭区间。
- 查找过程中访问到的对象才会加锁。
优化
- 索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为行锁。
- 索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。
bug
- 唯一索引上的范围查询会访问到不满足条件的第一个值为止。
案例附带知识点:
- select in share lock mode 覆盖索引 不会锁主键 for update 会锁主键
- 查询使用覆盖索引时,主键不需要加锁。
- 范围查询必须找出一个不满足条件之后才会才停止 (5 < c < 15 stop =16)
- 非唯一索引的范围不需要优化
- 当结果集条数与limit数目一致时,将不会再继续往后遍历数据。
- 向右为正序遍历 当倒序返回时 优化2则不会生效。
- next-key lock 实际是分两步走的 先实行GAP lock 再进行ROW lock
RC级别中也有GAP
在RC级别下语句执行过程中加上的行锁,在语句执行完成后,就要把“不满足条件的行”上的行锁直接释放了,不需要等到事务提交。因此读提交隔离级别下,锁的范围更小,锁的时间更短,这也是不少业务都默认使用读提交隔离级别的原因。
(22讲)
短连接模型
正常的短连接模式就是连接到数据库后,执行很少的SQL语句就断开,下次需要的时候再重连。
短连接模型存在一个风险,就是一旦数据库处理得慢一些,连接数就会暴涨。在业务高峰期的时候,就可能出现连接数突然暴涨的情况。
max_connections
-
max_connections参数,用来控制一个MySQL实例同时存在的连接数的上限,超过这个值,系统就会拒绝接下来的连接请求,并报错提示“Too many connections”。
-
max_connections的计算,不是看谁在running,是只要连着就占用一个计数位置。
处理连接数过高的优化方式
- 先处理掉那些占着连接但是不工作的线程。
- 减少连接过程的消耗。(让数据库跳过权限验证阶段:重启数据库,并使用–skip-grant-tables参数启动 风险极高)
慢查询性能问题
有三种可能:
- 索引没有设计好
- 语句没写好
- mysql 没有选对索引