复合索引中范围查询会截断右侧列的索引使用:因B+树按字典序嵌套排序,范围条件破坏前导列确定性,导致后续列全局无序,无法定位,只能全量扫描。

复合索引的B+树结构决定了范围查询会中断后续列的有序性
MySQL的复合索引底层是B+树,数据按索引定义顺序严格字典序排序:先排第一列,第一列相同时再排第二列,以此类推。这种“嵌套有序”只在前导列值完全相等的前提下成立。一旦某列用了>、、<code>BETWEEN或LIKE 'abc%'这类范围条件,就无法锁定一个确定的前导值区间——它会跨多个“前导值分组”,导致后续列天然失去全局有序性。
比如索引INDEX (a, b, c)中,a = 1 AND b > 2匹配的行可能来自(a=1,b=3)、(a=1,b=4)、(a=1,b=5)等多个子序列,每个子序列内的c是有序的,但拼起来的全部c值(如c=7、c=1、c=9)是乱序的。优化器无法用c = 5做二分或指针跳跃定位,只能对中间结果全量扫描。
EXPLAIN里key_len变短和Using where是右侧列失效的直接证据
执行EXPLAIN时,如果看到key_len比预期小(例如索引三列共20字节,但key_len只显示8),说明只有前N列被真正用于索引查找;同时Extra字段出现Using where,代表后续过滤是在回表后逐行做的,不是索引内完成的。
-
WHERE a = 1 AND b > 2 AND c = 5→key_len只含a和b长度,c不参与索引定位 -
WHERE a > 1 AND b = 2 AND c = 5→key_len可能只含a长度,b和c全失效 -
WHERE a = 1 AND b IN (2,3,4) AND c = 5→IN不算范围,b和c仍可走索引
调整索引列顺序比改写WHERE条件更有效
很多人误以为把WHERE里的条件顺序调换(比如写成WHERE b = 2 AND a > 1)就能让b也走索引,其实没用——MySQL优化器会自动重排条件,真正起作用的是索引本身的列顺序。
正确做法是根据查询模式反推索引设计:
- 高频等值查询的高选择性列(如
user_id、status)放最左 - 大概率范围查询的列(如
created_at、amount)尽量靠右 - 如果业务同时存在
WHERE a = ? AND c = ?和WHERE b > ? AND c = ?,宁可建两个窄索引:INDEX(a,c)和INDEX(b,c),别硬塞进一个INDEX(a,b,c)
LIKE 'xxx%'不算范围,但LIKE '%xxx'会让整列索引失效
LIKE 'abc%'属于等值前缀匹配,MySQL能利用索引的前缀有序性,不触发右侧截断;但LIKE '%abc'或LIKE '%abc%'会让该列索引直接失效,连最左前缀都用不上。
注意:LIKE是否触发范围逻辑,只看通配符位置,和字段类型、数据量无关:
-
name LIKE 'John%'→ 可用索引,且不影响后续列 -
name LIKE '%John'→ 当前列索引失效,若在复合索引中间,后续列也全丢 -
name LIKE 'J%h%n'→ 实际等价于'J%',仍可用前缀,但MySQL 8.0+才支持部分优化


















