根本原因是查询条件导致索引失效,如函数操作、LIKE前导通配符、隐式类型转换、索引列运算或联合索引未遵循最左前缀原则;FORCE INDEX仅适用于临时诊断,治本需更新统计信息、重写SQL或优化索引设计。

EXPLAIN 显示 type=ALL 但明明有索引,为什么没走?
根本原因往往不是 MySQL 拒绝用索引,而是查询条件让索引失效。比如对 name 字段建了索引,但写成 WHERE UPPER(name) = 'ABC',MySQL 无法下推函数计算到索引 B+ 树里,只能全表扫描。
常见踩坑点:
-
LIKE开头带通配符:WHERE name LIKE '%abc'—— 索引无法从左匹配,直接失效 - 隐式类型转换:
WHERE user_id = '123'(user_id是INT),MySQL 会把字段转成字符串比对,放弃索引 - 在索引列上做运算:
WHERE year(create_time) = 2024,哪怕create_time有索引也白搭 - 联合索引顺序错位:
INDEX(a,b,c),但只查WHERE b = 1 AND c = 2,跳过最左前缀a,索引用不上
用 FORCE INDEX 强制走某个索引靠谱吗?
靠谱,但只该作为临时诊断或极少数明确优化场景的手段,不是常规解法。MySQL 优化器选错索引通常意味着统计信息过期、数据分布异常,或者 SQL 本身写法有问题。
实操建议:
- 先运行
ANALYZE TABLE table_name更新统计信息,再看EXPLAIN是否改善 - 确认
FORCE INDEX后实际执行时间是否真变快——有时候强制走索引反而更慢(比如返回 90% 行数时,全表扫描可能比回表更快) - 语法很简单:
SELECT * FROM users FORCE INDEX (idx_status_created) WHERE status = 1 AND created > '2024-01-01'; - 注意:如果强制的索引根本覆盖不了查询条件(比如
WHERE里用了没被索引的字段),MySQL 仍会报错或退化为全表扫描
USE INDEX 和 IGNORE INDEX 的真实作用边界
USE INDEX 不是“必须用”,而是“只允许从这些索引里选”;IGNORE INDEX 是“禁止用这几个”,但优化器仍可能选其他索引或全表扫。它们都只是约束选项,不等于指令。
典型误用场景:
- 写了
USE INDEX (idx_a),但idx_a不包含WHERE所有字段,MySQL 可能默默忽略它,改用idx_b或全表扫 - 在
JOIN中对驱动表加IGNORE INDEX,结果被驱动表因关联字段缺失索引,整体性能雪崩 -
IGNORE INDEX对主键无效——MySQL 总是可能用主键做聚簇索引查找,你拦不住
真正稳住执行计划的三个动作
靠 hint 强制是治标,更新统计、重写 SQL、调整索引才是治本。尤其当线上执行计划突然漂移,大概率是数据量突增或统计信息滞后。
优先做这三件事:
- 检查
information_schema.STATISTICS中对应索引的CARDINALITY值是否明显失真(比如百万级表显示唯一值才几百) - 把模糊查询改成前缀匹配:
WHERE name LIKE 'abc%'→ 可走索引;实在要后缀匹配,考虑生成冗余倒序字段 + 索引 - 对高频查询字段,宁可多建一个单列索引,也别依赖联合索引中非最左字段的查询——联合索引本质是“排序优先”,不是“字段集合”
执行计划不是配置项,是数据、SQL、索引、统计信息共同作用的结果。任何单点干预都可能被另一端打破。


















