联合索引中范围查询(如>、<、BETWEEN、LIKE 'abc%')导致右侧字段失效,是因B+树字典序排序特性决定的:等值路径才能保持后续字段有序,范围查询破坏单点定位能力,使右侧字段无法索引查找;可用key_len和Extra验证失效程度。

联合索引中范围查询(如 >、<、BETWEEN、LIKE 'abc%')会让其右侧所有字段“失效”,这不是 MySQL 的缺陷,而是 B+ 树索引结构决定的必然行为。
失效的根本原因:B+ 树无法继续精确定位
联合索引 (a, b, c) 的数据在 B+ 树中是按字典序严格排序的:先排 a,a 相同再排 b,a 和 b 都相同才排 c。这种嵌套有序性只在“等值路径”上成立。
- 当条件是
a = 1 AND b = 2,MySQL 可以快速跳到唯一子树分支,c仍保持局部有序,可继续用索引过滤 - 但换成
a = 1 AND b > 2,系统必须扫描该a=1分支下所有b > 2的叶子节点——这些节点中c的值是杂乱无序的(因只按a,b排序) - 此时
c = 'x'就无法再靠索引二分查找,只能回表后逐行判断,即“不走索引”
哪些操作算“范围查询”,会触发右侧失效
关键看是否破坏“单点定位能力”:
-
会截断右侧:
>、>=、<、<=、BETWEEN、LIKE 'prefix%'、!=、NOT IN、IS NOT NULL -
不截断右侧:
=、IN(本质是多个等值)、IS NULL -
根本不用索引:
LIKE '%abc'、LIKE '%abc%'(无法利用前缀有序性)
怎么确认第三列到底有没有生效
别只看 key 列,重点看两个字段:
-
key_len:显示实际使用的索引字节数。比如INT占 4 字节,VARCHAR(50) utf8mb4约占 202 字节。若(a,b,c)索引预期总长 210 字节,但key_len = 206,说明只用了前两列 -
Extra:若出现Using where且没有Using index condition,大概率是右侧字段被过滤而非索引下推
如何让右侧字段尽量“保得住”
核心思路是调整字段顺序,把容易范围查询的列往右放:
- 高频等值字段(如
tenant_id、status)放最左 - 可能范围查询的字段(如
create_time、amount)放中间或最右 - 如果常查
a = ? AND c = ?,而b多为范围,就建(a, c, b)而非(a, b, c) - 避免反模式:比如
(created_at, status)—— 一用时间范围,status就废了;应改为(status, created_at)


















