mysql工程死锁问题
业务场景
员工表,有两个字段organ_id和area_id
以下两个sql语句同时执行
update emp_employee set deaprtment_id=12 where deaprtment_id=4 and area_id=4;
update emp_employee set deaprtment_id=12 where deaprtment_id=44 and area_id=4;
上面两条语句分别被事务a和事务b执行,在建立索引时分别单独建立了索引
死锁流程分析
从图上分析死锁的加锁流程:
- a通过deaprtment_id索引锁住了deaprtment_id为4的索引项
- b通过deaprtment_id索引锁住了deaprtment_id为44的索引项
- a回表锁住聚簇索引中id为1的索引项
- b回表锁住聚簇索引中id为2的索引项
- a通过area_id索引树锁住了area_id为4的索引项
- b通过area_id索引树找到了area_id为4的索引项,但是没法上锁,因为当前已经被a上锁了
- a通过回表试图锁住area_id为4对应的聚簇索引中id为1和2的索引项,但此时id为1的索引项已经被b锁住了,a需要b释放锁, 但序号6中已经提到b已经因为和a争抢area_id为4的索引项而被阻塞了,这时会产生死锁。
mysql如何处理死锁:
MySQL检测到死锁后,会自动回滚代价更低的那个事务,如上边的时序图中,事务b持有的锁比事务a少,则MySQL就将事务b进行了回滚。
应当如何解决:
对deaprtment_id和area_id建立复合索引,该情境下建立联合索引,a和b都不会对无关行上锁。
建议:索引不应该建立在重复比较多的字段上也是有这个原因,因为使用索引时锁定的数据行会比较多
回表
回表发生在非聚簇索引上,拿到非聚簇索引中的主键值再到主键索引树上查找完整的记录数据。
索引覆盖
只要在一棵b+树上就可以找到要sql的值,不需要回表
索引下推
使用联合索引的情况
比如我们建立一个联合索引(name,age)有如下sql:
select * from user where name = "李四" and age=20
不使用索引下推的情况:
查找到name=”李四”,获取主键值,再进行回表查询,再判断age是不是等于20
使用索引下推:
查找到name=”李四”,不需要回表,因为可以获取到年龄是不是等于20,可以直接在索引树找到
索引合并
一条SQL中使用两个或多个索引,查出来的数据集取交集或并集。
ps:mysql各种锁链接