联合索引第三列未生效是正常现象,因范围查询(>、

联合索引只用了前两列,第三列没走索引
这通常不是 bug,而是 B+ 树索引的固有行为:一旦出现范围查询(>、、<code>BETWEEN、LIKE 'abc%'),其右侧所有列就“断连”了。索引 idx_a_b_c(a, b, c) 下,WHERE a = 1 AND b > 10 AND c = 'x' 中的 c 不会生效——key_len 只显示前两列长度,Extra 里也不会出现 Using index condition。
- 验证方式:用
EXPLAIN FORMAT=TRADITIONAL查看key_len值是否匹配预期(如INT占 4 字节,VARCHAR(50)utf8mb4 约占 202 字节) - 修复思路:把高频等值条件字段尽量左置,范围字段靠右;若常查
a = ? AND c = ?,且b多为范围,可建idx_a_c_b(a, c, b) - 注意:MySQL 5.7 不支持索引下推(ICP)对所有场景生效,8.0+ 更可靠,但依然受范围中断限制
WHERE 里写了 c = 'x',但 EXPLAIN 显示 key 为 NULL
最可能的原因是跳过了最左列。联合索引 idx_name_age_city(name, age, city) 必须从 name 开始匹配,WHERE age = 25 AND city = 'Beijing' 直接触发全表扫描(type = ALL),因为 B+ 树无法定位起始页——就像电话簿不先选省,就找不到市和人。
- 检查
EXPLAIN的possible_keys是否为空,若为空,说明优化器根本没考虑该索引 - 不要依赖优化器自动重排条件顺序:虽然
WHERE age = 25 AND name = 'Li'有时能命中,但不保证稳定;显式按索引顺序写更可靠 - 如果业务确实高频查
age,重建索引为idx_age_name_city(age, name, city)是可行方案,但需评估写入开销和现有查询是否受影响
明明加了索引,EXPLAIN 却显示 type = ALL
这未必是索引没建,大概率是隐式类型转换或函数操作让索引“形同虚设”。例如字段 user_id 是 INT,但查询写成 WHERE user_id = '10086',MySQL 会悄悄给列加 CAST(),等价于在索引列上用了函数,直接失效。
- 用
SHOW CREATE TABLE确认字段类型,再比对应用层传参类型(比如 MyBatis 的@Param("uid") String uid就危险) - 避免在 WHERE 中对索引列做任何运算:
amount * 2 > 100、YEAR(create_time) = 2024、UPPER(email) = 'A@B.COM'全部失效 - 字符集/排序规则不一致也会跳过索引,比如
utf8mb4_bin列与utf8mb4_0900_as_cs连接时
ORDER BY 触发 Using filesort,但 WHERE 已走索引
这不代表索引完全没用,而是 MySQL 无法用同一个索引同时满足过滤和排序。例如索引是 (a, b),但查询是 WHERE a = 1 ORDER BY c,c 不在索引里,必然要 Using filesort。
- 若既要
WHERE又要ORDER BY,优先把排序字段放进联合索引右侧,如idx_a_c(a, c)支持WHERE a = 1 ORDER BY c -
SELECT *容易破坏覆盖索引,改用明确字段列表(如SELECT id, a, c)可消除Using filesort(前提是这些字段都在索引中) - MySQL 5.7 不支持混合 ASC/DESC 排序利用索引,
ORDER BY a ASC, b DESC在旧版本中无法走(a,b)索引
联合索引的“部分生效”不是偶然现象,而是 B+ 树结构 + 查询优化器决策共同作用的结果。最容易被忽略的是:范围查询中断后续列、最左列缺失、以及看似无关的类型不匹配——它们不会报错,只会默默退化为全表扫描。











