联合索引范围查询会“切断”右侧索引,因B+树按最左前缀严格字典序嵌套排序:仅当前导列全等值时,后续列才有序;一旦某列出现范围条件(如>、

范围查询为什么直接“切断”右侧索引
因为联合索引的 B+ 树是按字典序严格嵌套排序的:先排第一列,该列值相同时再排第二列,以此类推。这种有序性只在“前导列完全等值”的路径上成立。一旦某列用了 >、、BETWEEN 或 LIKE 'abc%',MySQL 就无法精确定位到一个连续子树,而必须扫描多个分支——这些分支里,后续列的值天然不再全局有序。
-
a = 1 AND b > 10 AND c = 5:能用a定位子树,b > 10在该子树内遍历,但所有匹配的叶子节点中c是杂乱的(比如 c=3、c=9、c=1),优化器没法跳转,只能回表后逐行过滤 -
IN不触发截断,因为它等价于多个=,每条路径仍保持后续列有序;但!=、NOT IN、IS NOT NULL通常被优化器视作全范围扫描,同样让右侧失效 -
LIKE 'xxx%'算等值前缀,不破坏有序性;但LIKE '%xxx'连该列本身都失效,不参与最左前缀判断
范围出现在不同位置时,索引利用程度差异极大
同一联合索引 INDEX (sn, name, age),范围条件的位置决定能用多少索引:
-
sn = 'S001' AND name = '张三' AND age > 25:前两列走索引,age仅自身无法利用有序性(但不拖累前面) -
sn = 'S001' AND name > 'A' AND age = 25:sn有效,name范围扫描,age完全失效(右侧列全部丢) -
sn > 'S001' AND name = '张三' AND age = 25:整个索引几乎退化为type=ALL,因为最左列一范围,后面就彻底失去锚点
如何验证右侧是否真的失效
别只看 key_len,重点结合 Extra 字段和实际执行计划:
- 查
key_len:比如索引(a,b,c)各占 4 字节,key_len=8表示只用到了a和b,c没参与索引查找 - 看
Extra:出现Using where且没Using index,说明后续列是在回表后过滤的,不是索引内完成的 - 用
EXPLAIN FORMAT=TREE(MySQL 8.0+)可直观看到“range access on …”停在哪一层
重构索引顺序不能解决所有问题
把高频范围列挪到右边看似合理,但要注意业务真实分布:
- 如果
WHERE status IN (1,2) AND created_at > '2026-01-01'是主查询模式,建INDEX (status, created_at)比(created_at, status)更稳——因为IN不截断,created_at虽范围但至少能用上 - 但如果
created_at查询总是单日或极窄区间(如created_at BETWEEN '2026-09-28' AND '2026-09-28 23:59:59'),它实际接近等值,放中间也未必差 - 真正难处理的是低选择性字段(如
gender)+ 范围组合,此时无论怎么调序,优化器都可能直接放弃索引
最易被忽略的一点:即使 key_len 显示用了全部列,只要 Extra 里有 Using where 且没有 Using index condition,就说明右侧列没走索引下推(ICP),仍在服务层过滤——这在高并发场景下会放大 IO 和 CPU 压力。











