死锁日志
1 | 2021-09-02T17:29:31.339235+08:00 10137065 [Note] InnoDB: Transactions deadlock detected, dumping detailed information. |
表结构
1 | CREATE TABLE `t_user_xxx_2` ( |
四种类型的行锁
- 记录锁,间隙锁,Next-key 锁和插入意向锁。这四种锁对应的死锁日志各不相同,如下:
- 记录锁(LOCK_REC_NOT_GAP):
lock_mode X locks rec but not gap
- 间隙锁(LOCK_GAP):
lock_mode X locks gap before rec
- Next-key 锁(LOCK_ORNIDARY):
lock_mode X
- 插入意向锁(LOCK_INSERT_INTENTION):
lock_mode X locks gap before rec insert intention
- 记录锁(LOCK_REC_NOT_GAP):
分析
- 通过explain分析
explain SELECT 1 FROM t_user_xxx_2 WHERE userId = xxxx AND type = 2 AND pId = 434444
得出以下 - 语句的type是index_merge,Extra的信息是Using intersect(idx_user_type,idx_pId),执行计划走了index_merge优化,单个语句通过两个索引(idx_userId_type,idx_pId)来提取记录集合并取交集获得最终结果集。
解决方式
- 关闭:index_merge_intersection=off (解决思路:直接关闭MySQL的优化)
- 删掉多余的索引idx_pId(解决思路:建立合理的索引)— 此案例中,根据业务实际情况,使用该方案解决
- 先查,再使用主键或唯一索引来更新(解决思路:缩小索引范围) (推荐)
- 强制走idx_userId_type 索引
- 添加userId + type + pId的组合索引,这样就可以避免掉index merge
Reference
- [MySQL update use index merge(Using intersect) increase chances for deadlock]
(https://developer.aliyun.com/article/8963) - https://dev.mysql.com/doc/refman/8.0/en/index-merge-optimization.html#index-merge-intersection