用EXPLAIN定位慢查询索引问题需重点关注type、key、rows和Extra四列:type为ALL/index表示全表/索引扫描;key为NULL说明未命中索引;rows远大于实际返回行数反映索引选择性差;Extra含Using filesort/temporary表明排序分组未走索引。

如何用 EXPLAIN 快速定位慢查询的索引问题
直接看 EXPLAIN 输出比盲猜有效得多。重点盯住 type、key、rows 和 Extra 这四列:
-
type值为ALL或index:说明走了全表扫描或全索引扫描,大概率缺合适索引 -
key为NULL:没命中任何索引,哪怕表上有索引也可能是条件写法导致失效(比如对字段做函数操作) -
rows明显大于实际返回行数:索引选择性差,或用了前缀索引但区分度低 -
Extra出现Using filesort或Using temporary:ORDER BY / GROUP BY 没走索引,可能需要覆盖索引或调整排序字段顺序
复合索引设计时,字段顺序为什么不能随便调换
MySQL 的 B+ 树索引是按字段顺序逐级分裂的,等价于一个嵌套字典:{a: {b: {c: [...]}}}。这意味着:
- 只查
b或c字段,该索引完全无效 - 查
a = ? AND b > ?可以用到a和b,但c后面的范围条件会截断索引下推 - 查
a IN (?, ?) AND b = ?时,b无法继续用于索引查找(IN 是范围操作,会中断后续字段的等值匹配) - 高频过滤字段放最左,排序/分组字段尽量靠右并保持顺序一致(如
WHERE a = ? ORDER BY b, c→ 索引建为(a, b, c))
SELECT * 和覆盖索引之间的性能鸿沟
即使有索引,SELECT * 很可能让优化器放弃使用它——因为回表成本太高。覆盖索引指查询所需所有字段都在索引中,无需回主键索引查数据行。
系统功能强大、操作便捷并具有高度延续开发的内容与知识管理系统,并可集合系统强大的新闻、产品、下载、人才、留言、搜索引擎优化、等功能模块,为企业部门提供一个简单、易用、开放、可扩展的企业信息门户平台或电子商务运行平台。开发人员为脆弱页面专门设计了防刷新系统,自动阻止恶意访问和攻击;安全检查应用于每一处代码中,每个提交到系统查询语句中的变量都经过过滤,可自动屏蔽恶意攻击代码,从而全面防止SQL注入攻击
- 判断是否覆盖:
EXPLAIN中Extra出现Using index(注意不是Using index condition) - 常见误操作:给
(a, b)建了索引,但查询写成SELECT a, b, c FROM t WHERE a = ?→c不在索引里,必然回表 - 解决方案:把经常一起查的字段加进索引末尾(如改成
(a, b, c)),或明确只查索引包含的字段 - 注意:大字段(
TEXT、BLOB)不能建索引,也不适合放进复合索引,否则索引体积暴涨
哪些看似合理却让索引彻底失效的写法
这些写法会让 MySQL 直接跳过索引,哪怕字段上有完美索引也没用:
- 在索引字段上使用函数:
WHERE YEAR(create_time) = 2023→ 改成WHERE create_time >= '2023-01-01' AND create_time -
隐式类型转换:
WHERE mobile = 13812345678(mobile 是VARCHAR)→ 数字会被转成字符串再比较,触发全表扫描;应统一写成字符串'13812345678' - LIKE 以通配符开头:
WHERE name LIKE '%abc'→ 无法使用 B+ 树的有序特性;若必须模糊查前缀,确保写成LIKE 'abc%' - OR 连接不同字段:
WHERE a = 1 OR b = 2→ 即使a和b都有索引,也可能全表扫;考虑拆成 UNION 或补上联合索引(a,b)并重写逻辑
EXPLAIN SELECT id, name FROM user WHERE status = 1 AND created_at > '2023-01-01' ORDER BY score DESC;
如果这个查询慢,先看 EXPLAIN 是否走了 status 索引;如果没有,优先建联合索引 (status, created_at, score) —— 注意顺序不是随意排的,而是按「过滤→范围→排序」的层级来组织。漏掉任何一个环节,都可能让优化器重新评估成本并弃用索引。









