MySQL 行锁等待优化需缩短事务时间、确保索引生效、统一更新顺序、合理设置隔离级别;避免长事务、无索引 DML、乱序更新及不必要锁。

MySQL 行锁等待主要发生在高并发更新同一行数据时,核心优化方向是缩短事务持 有锁 的时间、减少锁冲突概率、合理设计索引与事务逻辑。
缩短事务执行时间
长事务会持续持有行锁,大幅增加等待概率。应避免在事务中做耗时操作(如远程调用、大循环、文件读写)。
- 把非数据库操作(如日志记录、消息发送)移出事务块
- 拆分大事务:例如批量更新 10 万行,改为每次 1000 行 + 显式提交
- 检查慢查询日志,定位并优化事务内执行慢的 SQL(特别是未走索引的 UPDATE/DELETE)
确保 DML 语句走索引
无索引的 UPDATE 或 DELETE 会退化为表级扫描,不仅锁住目标行,还可能锁住大量无关行(甚至整个聚簇索引),引发连锁等待。
- 使用 EXPLAIN 确认 WHERE 条件命中有效索引(type 字段至少为 range,key 显示实际索引名)
- 避免在索引列上使用函数或 隐式类型转换 (如WHERE DATE(create_time) = ‘2024-01-01’ 会失效)
- 联合索引注意最左前缀原则,确保查询条件覆盖索引开头字段
按主键或唯一索引顺序更新
多线程并发更新不同行时,若更新顺序不一致(如线程 A 先更新 id= 5 再 id=2,线程 B 相反),容易造成死锁或相互等待。
- 业务层统一按主键升序(或降序)排列 待更新 ID 列表,再批量执行
- 避免“先 SELECT 再 UPDATE”的模式,改用 SELECT … FOR UPDATE 加锁时带上 ORDER BY 主键
- 对同一业务逻辑涉及的多行更新,尽量在单条 SQL 中完成(如 INSERT … ON DUPLICATE KEY UPDATE)
合理设置隔离级别与锁类型
并非所有场景都需要默认的 REPEATABLE READ。适当降级可减少锁强度和范围。
- 确认业务是否真的需要可重复读:若无幻读敏感逻辑,可设为 READ COMMITTED
- 只读查询无需加锁,显式使用 SELECT … LOCK IN SHARE MODE 或FOR UPDATE前务必评估必要性
- 用 SELECT … FOR UPDATE SKIP LOCKED 跳过已被锁的行(适合队列类消费场景)