You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL多列唯一键带OR条件查询为何触发next-key锁

OR条件触发唯一键next-key锁的原因

InnoDB 只有在唯一索引做单点等值匹配、能明确确认最多只返回1条唯一记录的场景下,才会触发「仅加记录锁、不加间隙锁」的优化,这个优化的前提非常严格:必须是唯一索引的所有索引列都用AND连接做常量等值匹配,查询条件可以直接在索引上定位到唯一的一个点,不需要做范围扫描。

两个测试场景的加锁逻辑差异

  • 场景1:c1=1 and c2=2
    该条件是联合唯一键unique_key_1的全列等值精确匹配,优化器可以直接在索引上做单点查询,明确知道最多只有1条符合条件的记录,完全满足官方文档描述的优化前提,因此只给匹配到的行加记录锁,不会加任何间隙锁,自然不会出现supremum pseudo-record相关的锁记录。
  • 场景2:c1=1 and (c2=1 or c2=2)
    该条件中用OR连接c2列的两个等值条件,InnoDB的锁逻辑不会做语义拆分——不会把这个条件拆成两个独立的唯一键单点查询分别加锁,而是会将其识别为「c1=1前提下c2列的范围扫描」:扫描从c2的最小值开始,一直向后遍历直到找到第一个不满足条件的记录才会停止。
    由于测试表中c1=1的记录最大c2值为2,扫描遍历完(1,2)这条记录后,还需要继续向后检查是否存在其他符合条件的记录,会一直走到索引末尾的虚拟记录supremum pseudo-record才会停止,因此会按照范围扫描的加锁规则,给整个扫描路径覆盖的区间加next-key锁,最终就会观测到supremum pseudo-record上的锁。

补充说明:哪怕你把OR条件改写为c2 IN (1,2),最终加锁结果也完全一致。InnoDB的加锁是跟着实际索引扫描路径走的,不会根据查询结果的语义做优化——只要查询条件不能直接定位到唯一索引上的单个点,哪怕逻辑上能确定所有匹配结果都是唯一记录,也会按照范围扫描的规则加next-key锁,覆盖扫描路径上的所有间隙。

完整测试SQL

DROP TABLE `t`;

CREATE TABLE `t` (
  `c1` int,
  `c2` int,
  UNIQUE KEY `unique_key_1` (`c1`, `c2`)
) ENGINE=InnoDB;


insert into t (c1,c2) values (1,1);
insert into t (c1,c2) values (1,2);



-- 场景1
start transaction;

select * from t where c1=1 and c2=2 LOCK IN SHARE MODE;

SELECT 
    OBJECT_NAME, INDEX_NAME, LOCK_DATA
FROM
    performance_schema.data_locks
WHERE
    OBJECT_NAME = 't'
        AND INDEX_NAME = 'unique_key_1'
        AND LOCK_DATA = 'supremum pseudo-record';

commit;


-- 场景2
start transaction;

select * from t where c1=1 and (c2=1 or c2=2) LOCK IN SHARE MODE;

SELECT 
    OBJECT_NAME, INDEX_NAME, LOCK_DATA
FROM
    performance_schema.data_locks
WHERE
    OBJECT_NAME = 't'
        AND INDEX_NAME = 'unique_key_1'
        AND LOCK_DATA = 'supremum pseudo-record';

commit;

内容的提问来源于stack exchange,提问作者Evripides Evripidou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 06:09:10