EXPLAIN是唯一可靠方式判断索引是否生效,需在SELECT前添加并观察type(非ALL)、key(非NULL)、rows(显著小于总行数)和Extra(无Using filesort/temporary)字段。

加索引不是“给表加”,而是“给查询条件加”——索引是否生效,取决于你 WHERE、JOIN、ORDER BY 和 GROUP BY 中实际用到的列及顺序。
怎么看当前查询有没有走索引
执行 EXPLAIN 是唯一可靠方式。在你的 SELECT 语句前加上它,观察 type、key、rows 和 Extra 字段:
-
type是ALL?说明全表扫描,大概率没走索引 -
key为空?表示没用上任何索引 -
rows值接近表总行数?说明索引效果差或没命中 -
Extra出现Using filesort或Using temporary?常意味着排序/分组无法利用索引完成
注意:不要只看 EXPLAIN 的 possible_keys,它只是候选,真正生效的是 key。
复合索引的列顺序为什么关键
MySQL 只能高效使用索引的最左前缀。比如建了 INDEX idx_user_status_time (user_id, status, created_at):
- ✅ 能用上:
WHERE user_id = ?、WHERE user_id = ? AND status = ?、WHERE user_id = ? AND status = ? ORDER BY created_at - ❌ 用不上:
WHERE status = ?(跳过首列)、WHERE user_id = ? AND created_at > ?(中间断开) - ⚠️ 注意:范围查询(
>、<、BETWEEN)之后的列无法用于索引查找,但可能用于排序(如ORDER BY)
所以把高选择性、且查询中必出现的列放在前面;排序字段如果固定,可放最后补全覆盖。
哪些情况加了索引也白加
索引不是万能加速器,这些场景下即使建了索引,优化器也可能弃用或效果极差:
- 列上用了函数或表达式:
WHERE YEAR(created_at) = 2024→ 应改写为WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01' - 隐式类型转换:
WHERE phone = 13812345678(phone 是VARCHAR)→ 改成字符串引号:'13812345678' - 低选择性字段单独建索引:
gender(只有 'M'/'F'),除非配合其他列构成复合索引,否则基本无效 - 数据量极小(比如几百行)的表,全表扫描比索引回表更快,优化器会直接忽略索引
ALTER TABLE 加索引时要注意什么
线上加索引是高风险操作,尤其大表:
- MySQL 5.6+ 支持
ALGORITHM=INPLACE,但仍可能锁表(取决于存储引擎和操作类型);8.0 默认更友好,但DROP INDEX+ADD INDEX组合仍可能触发重建 - 务必在业务低峰期操作,并提前在从库或影子库验证耗时
- 避免在单条
ALTER中同时增删多个索引,拆成独立语句便于中断和回滚 - 建完立即
ANALYZE TABLE(尤其 InnoDB),让优化器更新统计信息,否则可能继续沿用旧的执行计划
真正难的不是语法,是判断哪几个列、按什么顺序、在哪个查询路径下组合起来才真正被用到——这需要结合慢日志、EXPLAIN 和业务查询模式反复验证。


















