最左前缀原则规定:当联合索引中某列使用非等值查询(如>、

最左前缀原则如何限制范围查询后的列匹配
MySQL 的 B+Tree 索引结构决定了:一旦某个索引列参与了非等值查询(如 >、、<code>BETWEEN、!=),其右侧所有列在该查询中就无法被用于索引查找,哪怕它们本身有等值条件。
这不是 MySQL 的 bug,而是 B+Tree 的物理组织方式决定的——索引按联合键字典序排序,例如复合索引 (a, b, c) 存储的是 (1,1,1)、(1,1,2)、(1,2,1)、(2,1,1) 这样的有序序列。当执行 WHERE a = 1 AND b > 5 AND c = 10 时:
-
a = 1定位到子树起始位置 -
b > 5在该子树内做范围扫描,但此时c的值在内存中是“散列”的(比如(1,6,1)、(1,6,100)、(1,7,2)),无法跳转到某个固定的c = 10节点 - 所以
c = 10只能作为过滤条件(Extra: Using where),而非索引驱动条件
EXPLAIN 中 key_len 和 Extra 字段怎么看
判断多列索引是否“用全”不能只看 key 字段是否命中索引,关键要看 key_len 和 Extra:
-
key_len显示实际使用的索引字节数。例如utf8mb4的VARCHAR(50)最大占 202 字节(50×4+2),若key_len是 202,说明只用了第一列;若为 404,可能用了前两列(假设第二列也是同样类型) -
Extra: Using index表示覆盖索引(无需回表);Extra: Using where表示该条件未走索引,是 Server 层过滤 - 如果
Extra出现Using index condition,说明用了 ICP(Index Condition Pushdown),即部分条件下推到存储引擎层过滤,但仍是“非索引驱动”
哪些非等值操作会截断后续列
以下操作都会让 MySQL 停止向右扩展索引列匹配:
-
>、、<code>>=、、<code>、!= -
BETWEEN(即使两端都是常量,也视为范围) -
LIKE以通配符开头(LIKE '%abc')或中间带通配符(LIKE 'ab%c'),因为无法确定前缀边界 -
IS NULL/IS NOT NULL在某些版本中也会中断最左前缀(尤其当列允许 NULL 且统计信息不准时)
注意:IN 是等值集合,只要写法规范(如 WHERE a = 1 AND b IN (2,3) AND c = 4),c 仍可被索引使用;但 OR 拆分后若涉及不同列,优化器可能放弃复合索引。
想让后续列也生效?换思路,别硬扛
遇到 WHERE a = ? AND b > ? AND c = ? 这类查询,强行靠一个复合索引让三列都“驱动”基本不可行。更实际的做法是:
- 把高频等值 + 高频范围的组合前置:例如业务中
b的范围极窄(如状态枚举),可考虑建(a, b, c)索引,并接受c是过滤项 - 拆成多个等值路径:如果
b取值有限(如只有 3~5 个状态),改写为UNION ALL多个WHERE a = ? AND b = ? AND c = ?,每条都能走完整索引 - 冗余单列索引:为
c单独建索引,让优化器在必要时选择c索引 + 回表,再用a、b过滤(适合c选择性极高) - 避免在 OLTP 场景强求“全列索引驱动”:这类查询本质已偏向分析型,考虑物化中间结果或引入缓存层
真正容易被忽略的点是:很多人盯着 EXPLAIN 的 key 是否非空,却没看 key_len 是否随条件增加而变长——这才是判断“后续列有没有被索引真正用上”的铁证。











