联合索引未生效的根本原因是查询条件未满足最左前缀原则:若跳过最左列或中间列、使用范围查询、函数/表达式/隐式类型转换,均会导致索引部分或全部失效。

为什么联合索引没走,EXPLAIN 显示 type=ALL
根本原因是查询条件没触达联合索引的最左列,B+树找不到扫描起点。比如索引是 idx_user_age_city(user_id, age, city),但你只查 age = 25 或 city = '北京',MySQL 就只能全表扫——因为 age 和 city 在全局无序,无法定位。
跳过中间列导致后缀失效,比如 user_id = ? AND city = ?
这是最常被忽略的“半生效”陷阱:条件里有最左列 user_id,但跳过了 age 直接写 city,结果只有 user_id 走索引,city 完全失效。MySQL 不会自动“跳过缺失列去匹配后面的”,它只认连续前缀。
- ✅ 正确用法:
user_id = ? AND age = ?、user_id = ? AND age = ? AND city = ? - ❌ 无效写法:
user_id = ? AND city = ?(city不参与索引查找) - ⚠️ 注意:优化器会重排 WHERE 条件顺序,
age = ? AND user_id = ?依然能用完整索引,但前提是user_id存在且非范围查询
范围查询(>、
age > 25 这类条件会让索引“断在这一层”:前面的 user_id 和 age 还能用于定位数据块,但 city 的值在该块内不再有序,无法再用索引快速过滤或排序。
- 典型症状:
WHERE user_id = ? AND age > 25 AND city = ?→city不走索引;ORDER BY city→ 触发Using filesort - 解法不是硬加索引,而是按查询模式调整索引顺序,例如把高频等值查询的列往前放:
idx_user_city_age(user_id,city,age) - 如果
city经常用于等值 +age用于范围,这个新顺序就能让两者都生效
函数、表达式、隐式转换让最左列也失效
哪怕你写了 user_id = 'u001',如果字段是 VARCHAR 而你传入数字 123,MySQL 会隐式转成字符串再比对,但这个转换过程破坏了索引列的原始存储形式,导致无法走索引。
- 常见踩坑点:
WHERE YEAR(create_time) = 2023、WHERE UPPER(name) = 'JOHN'、WHERE user_id = 123(字段为字符串) - 正确做法:把计算移到右边,用范围替代函数,例如
create_time >= '2023-01-01' AND create_time - 类型必须严格一致——连引号都不能省:
user_id = 'u001'✅,user_id = u001❌(语法错误),user_id = 123❌(触发隐式转换)
最左匹配不是“写了最左列就万事大吉”,它是一条脆弱的链:缺一环、断一处、歪一点,整条链就掉链子。真正要盯住的,是查询条件和索引定义之间那几列的对齐关系,而不是堆砌更多索引。











