先查 EXPLAIN 看执行计划,type 为 ALL/index、key 为空或 key_len 偏小说明索引未用或未用全;LIKE '%abc'、字段加函数或计算均会导致索引失效。

WHERE 条件里字段没走索引?先查 EXPLAIN 看执行计划
MySQL 不会自动告诉你 WHERE 里的字段用没用上索引,得靠 EXPLAIN 主动看。不查就调,纯靠猜,十有八九在修幻觉。
常见错误现象:明明给 user_id 加了索引,但 SELECT * FROM orders WHERE user_id = 123 还是慢;或者加了联合索引 (status, created_at),但写成 WHERE created_at > '2024-01-01' 就完全失效。
-
EXPLAIN结果里type是ALL或index,基本等于全表/全索引扫描,得警惕 -
key字段为空,说明压根没选索引;key_len比预想的小,可能是只用了联合索引的前缀 - 注意
possible_keys和key的区别:前者是“可选”,后者才是“真用”
LIKE '%abc' 为什么索引失效?因为 B+ 树不支持后缀匹配
索引底层是 B+ 树,靠左前缀有序存储,LIKE 'abc%' 能用索引,LIKE '%abc' 或 LIKE '%abc%' 就不行——没法从树根往下定位起始点。
使用场景:搜索框模糊查用户昵称、商品标题等,前端输入“张三”,后端拼成 WHERE name LIKE '%张三%',性能直接崩。
- 能改前缀匹配就改,比如把搜索逻辑调整为“以…开头”,用
LIKE '张三%' - 实在要后缀查,考虑生成反向字段:加一列
name_reversed,存REVERSE(name),再建索引,查时也用REVERSE('张三') - 全文索引(
FULLTEXT)适合长文本关键词搜,但不适用于精确短字符串匹配,且仅 MyISAM/InnoDB 支持有限
WHERE 中对字段做函数或计算,索引立即失效
只要 WHERE 里出现 YEAR(created_at) = 2024、UPPER(name) = 'ADMIN'、id + 1 = 100 这类写法,对应字段的索引就作废——MySQL 无法把函数结果映射回原始索引值。
性能影响明显:一个百万级订单表,WHERE DATE(created_at) = '2024-05-20' 可能比 WHERE created_at >= '2024-05-20' AND created_at 慢几十倍。
- 日期范围尽量手写边界,别依赖
DATE()、HOUR()等函数 - 大小写比较统一存小写,查询也用小写,避免
LOWER()包裹 - 如果必须函数处理,且查询频繁,可建函数索引(MySQL 8.0.13+):
CREATE INDEX idx_name_lower ON users ((LOWER(name)))
联合索引的顺序不是随便排的:高区分度字段放前面不总对
老说法“把区分度高的字段放左边”在某些场景反而拖累。关键要看查询模式是否满足最左前缀原则,以及 WHERE 条件是否经常只用到右边字段。
例如:表有字段 status(只有 3 个值)、user_id(百万级唯一)、created_at(时间戳)。如果大部分查询是 WHERE user_id = ? AND status = ?,那索引 (user_id, status) 比 (status, user_id) 更实用;但如果还有大量 WHERE status = ? ORDER BY created_at DESC,那 (status, created_at) 才能覆盖排序。
- 优先按高频查询条件顺序建联合索引,而不是单看字段基数
- WHERE 中出现的字段顺序 ≠ 索引字段顺序,但必须满足最左连续匹配
- ORDER BY 和 GROUP BY 字段如果和 WHERE 共用索引,也能避免文件排序(
Using filesort),这点容易被忽略
索引不是越多越好,每个额外索引都增加写开销、占用磁盘、拖慢 INSERT/UPDATE。真正卡住查询的,往往不是缺索引,而是 WHERE 写法绕过了已有索引——盯紧 EXPLAIN 输出,比盲目加索引管用得多。


















