MySQL 5.7死锁问题求助:附xs_pv表结构详情
MySQL 5.7 异常死锁问题分析与排查
最近在MySQL 5.7环境里碰到了一个棘手的死锁问题,特意把细节和排查思路整理出来,供大家参考:
涉及的表结构
首先贴出问题涉及的xs_pv表完整结构:
CREATE TABLE `xs_pv` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `nh_id` int(10) unsigned NOT NULL COMMENT '小说编号', `day` date NOT NULL COMMENT '日期', `pv` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '页面浏览量', `uv` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '独立访客', `name` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`), KEY `nh_id` (`nh_id`), KEY `day` (`day`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
可能的死锁触发场景
结合InnoDB的锁机制,这个表出现死锁大概率和以下几种情况有关:
- 并发UPSERT操作冲突:如果业务中频繁对同一
nh_id+day组合执行INSERT ... ON DUPLICATE KEY UPDATE,但没有针对这两个字段的联合索引,InnoDB会扫描单列索引产生间隙锁或记录锁冲突 - 事务操作顺序不一致:不同并发事务的操作顺序颠倒(比如事务1先更新A记录再更新B记录,事务2先更新B记录再更新A记录),极易触发循环等待导致死锁
- 索引使用不合理:当前表只有
nh_id和day的单列索引,当查询/更新同时用到这两个字段时,可能走非最优索引,导致锁的范围被无端扩大
排查与解决建议
- 提取死锁核心信息:执行命令
SHOW ENGINE INNODB STATUS;,在输出的LATEST DETECTED DEADLOCK区块里,能看到死锁涉及的事务、SQL语句、锁类型等关键细节,这是定位问题的核心依据 - 添加针对性联合索引:如果业务逻辑中经常基于
nh_id和day做更新/查询,建议创建联合索引KEY idx_nh_day (nh_id, day),让InnoDB精准定位记录,大幅缩小锁的范围 - 优化事务执行逻辑:尽量缩短事务时长,避免在事务中执行无关操作;同时统一所有并发事务的操作顺序,比如都先处理
nh_id较小的记录,再处理较大的 - 调整UPSERT逻辑:如果是
INSERT ... ON DUPLICATE KEY UPDATE引发的死锁,可以拆分为“先查询(加FOR UPDATE锁)再更新/插入”的逻辑,同时严格控制事务范围
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

