MySQL索引生效需满足最左前缀原则且条件可下推;失效场景包括LIKE前置通配、字段运算、非首列IS NULL;建议将高频过滤字段置复合索引左侧,避免对索引列使用函数。

WHERE 条件写法直接影响索引是否生效
MySQL 不会因为字段上有索引就自动用上——它只在满足「索引最左前缀原则」且条件可下推时才走索引。常见失效场景包括:WHERE column LIKE '%abc'(前置通配)、WHERE column + 1 = 10(对字段做运算)、WHERE column IS NULL(对未建索引的列或复合索引非首列用 IS NULL)。
实操建议:
- 把常用于过滤的字段放在复合索引最左侧,比如查询习惯是
WHERE status = ? AND created_at > ?,索引应建为(status, created_at),而非反过来 - 避免在 WHERE 中对索引列使用函数,如
WHERE DATE(create_time) = '2024-01-01'→ 改成WHERE create_time >= '2024-01-01' AND create_time - IN 列表项不宜过多(一般不超过 500 个),否则优化器可能放弃索引走全表扫描;大量离散值过滤考虑分区或临时表
EXPLAIN 是判断索引是否被用上的唯一可靠方式
光看执行时间或“感觉快了”没用。EXPLAIN 输出里的 type、key、rows、Extra 四个字段最关键:如果 key 为 NULL,说明完全没走索引;type 是 ALL 表示全表扫描;Extra 出现 Using filesort 或 Using temporary 往往意味着排序/分组无法利用索引完成。
实操建议:
- 对每个核心查询都加
EXPLAIN前缀跑一遍,尤其上线前和慢查询优化时 - 注意
rows值是否远大于实际返回行数——这说明索引选择性差,可能需要调整索引列顺序或增加过滤条件 - 用
EXPLAIN FORMAT=JSON查看更详细的访问路径和成本估算,比如是否触发了索引合并(index_merge)
联合索引不是“多个单列索引”的简单叠加
建 (a,b,c) 索引后,能高效支持 WHERE a = ?、WHERE a = ? AND b = ?、WHERE a = ? AND b = ? AND c = ?,但对 WHERE b = ? 或 WHERE b = ? AND c = ? 完全无效。MySQL 5.7+ 虽支持索引下推(ICP),但前提是必须能定位到索引的最左前缀。
实操建议:
- 删除冗余索引:已有
(a,b)就不必再单独建(a);已有(a,b,c)通常也不需(a,b)(除非(a,b)覆盖查询更短) - 区分「查询过滤」和「排序/分组」需求:若常
ORDER BY a,b且WHERE c = ?,优先建(c,a,b)而非(a,b,c),让排序也能复用索引 - 对高基数字段(如 user_id)放前面,低基数字段(如 status)放后面,提升范围扫描效率
隐式类型转换会让索引彻底失效
这是线上最隐蔽的性能杀手之一。比如字段定义是 VARCHAR(32),但查询写成 WHERE user_id = 123(传入数字而非字符串),MySQL 会把每行 user_id 值转成数字比对,导致无法使用索引。错误日志里看不到报错,EXPLAIN 却显示 key=NULL。
实操建议:
- 参数类型必须和字段定义严格一致:字符串字段用
'123',数字字段用123,别依赖 MySQL 自动转换 - 检查应用 ORM 框架生成的 SQL,有些框架会默认把整数参数塞进字符串占位符,引发隐式转换
- 用
SHOW WARNINGS查看优化器重写后的语句,确认是否有CONVERT(... USING ...)类型转换操作
EXPLAIN 的输出。










