意向锁本身不互斥,真正导致阻塞的是范围查询触发的Next-Key锁或间隙锁;需通过EXPLAIN确认type=range,并用performance_schema.data_locks查LOCK_MODE含GAP或NEXT-KEY的锁。

意向锁本身不冲突,所谓“范围查询导致意向锁冲突”其实是误判——真正卡住你的,是范围扫描触发的大量行级锁或间隙锁,而意向锁(IX)只是它们的前置声明。
为什么 EXPLAIN 显示 type=range 就可能引发锁等待
当 WHERE id BETWEEN 100 AND 200 这类主键范围查询没走索引(比如字段类型隐式转换),InnoDB 会退化为全表扫描;即使走了主键索引,BETWEEN 或 >/< 仍会申请 Next-Key Lock(记录锁 + 间隙锁),锁住整个区间。
- 锁范围远超实际匹配行:例如
id > 100且 id=105 存在,则锁住 (105, +∞) 的间隙,后续插入 id=106 的事务会被阻塞 - 多个并发事务同时执行相同范围查询,各自加 IX 锁很快,但后续逐行加 X 锁时在同一批记录上排队
- READ COMMITTED 下间隙锁被禁用,但记录锁仍存在;REPEATABLE READ 下 Next-Key Lock 范围更大,冲突概率更高
主键等值 vs 范围查询的锁行为差异
主键等值查询(如 WHERE id = 105)只锁单行,Next-Key Lock 会退化为纯记录锁;而范围查询无法退化,必须覆盖区间。
- 等值命中:加 Record Lock(仅 id=105 这一行)
- 等值未命中:加 Gap Lock(如查 id=107 但不存在,则锁 (105, 110))
- 范围查询(
>,<,BETWEEN):无论是否命中,都加 Next-Key Lock,锁住起点到下一个索引值之间的全部间隙+记录 - UPDATE/DELETE 带范围条件时,意向锁(IX)瞬间获得,但行锁申请过程慢且易排队——你看到的“等待意向锁”,日志里写的是 IX,实际堵在后面那一步
如何快速定位是不是范围查询惹的祸
别只看 SHOW ENGINE INNODB STATUS\G 里的 LOCK_TRX_ID 和 LOCK_DATA,重点查执行计划和锁范围。
- 对问题 SQL 执行
EXPLAIN FORMAT=TRADITIONAL,确认type是range还是ref;如果是ALL或index,立刻检查 WHERE 条件是否用了函数、隐式转换、丢失最左前缀 - 用
SELECT * FROM performance_schema.data_locks查当前锁详情,关注LOCK_MODE字段:若出现X, GAP或X, REC_NOT_GAP组合,说明是范围查询引发的 Next-Key 锁 - 对比事务隔离级别:把 REPEATABLE READ 改成 READ COMMITTED 后,如果阻塞明显减少,基本可断定是间隙锁扩散导致
真正难处理的不是意向锁,而是范围查询下锁范围不可控——哪怕只改 1 行,也可能锁住几百行甚至整个索引段。优化方向永远优先落在索引设计和查询写法上,而不是调锁参数。


















