EXPLAIN能明确判断索引是否被使用:key为NULL表示未用索引,type为ALL/index说明全表或全索引扫描,Extra出现Using filesort或Using temporary提示排序/分组未走索引。

EXPLAIN 不是万能诊断器,但它能明确告诉你:这次查询到底有没有走索引、为什么没走、以及优化器在想什么。 直接看 key 列是否为 NULL,再结合 type 和 Extra,就能快速定位 90% 的索引失效问题,不用猜、不用试错。
怎么看 EXPLAIN 输出里索引是否真的被用了
关键就三列:key、type、Extra。其他字段辅助判断。
-
key列显示实际使用的索引名;如果是NULL,说明本次查询完全没用索引(注意:不是“没建”,是“没选”) -
type是性能风向标:ALL或index几乎等于全表扫描;range、ref、eq_ref才算有效利用了索引 -
Extra里出现Using filesort或Using temporary,往往意味着 ORDER BY 或 GROUP BY 字段没走索引,或索引覆盖不全 - 别只看
possible_keys——它只是候选列表,不代表真用了;真正干活的是key
WHERE 条件写法怎么让索引“罢工”
很多失效不是索引建得不对,而是 SQL 写法直接破坏了索引的可搜索性(non-sargable condition)。
- 对索引列用函数:
WHERE DATE(create_time) = '2026-08-10'→ 改成WHERE create_time BETWEEN '2026-08-10 00:00:00' AND '2026-08-10 23:59:59' - 隐式类型转换:
phone是VARCHAR,却写WHERE phone = 13812345678→ 必须加引号:WHERE phone = '13812345678' - 左模糊匹配:
WHERE name LIKE '%张'→ 索引失效;WHERE name LIKE '张%'可用索引 - OR 连接不同字段:
WHERE a = 1 OR b = 2,若只有idx_a没有idx_b,通常退化为全表扫描
联合索引顺序怎么影响 WHERE 和 ORDER BY
组合索引不是“多个字段堆一起”,它的结构决定了哪些条件能用、哪些被跳过。
- 索引
(status, created_at):支持WHERE status = 1、也支持WHERE status = 1 AND created_at > '2026-01-01',但WHERE created_at > '2026-01-01'完全无效 - 如果查询带
ORDER BY created_at DESC,且status是等值条件,那(status, created_at)能同时满足 WHERE + ORDER BY,避免Using filesort - 范围查询后列失效:
WHERE status = 1 AND created_at > '2026-01-01' AND amount > 100中,amount无法使用该联合索引 - 区分度高的字段放左边更合理——比如
user_id(高区分度)比status(低区分度,如只有 0/1)更适合放联合索引首位
为什么测试库走索引,线上却全表扫描
执行计划不是静态配置,它依赖实时数据分布和统计信息。同一句 SQL,在不同环境可能生成完全不同计划。
- 数据量差异大:测试表只有 1000 行,优化器觉得全表扫描更快;生产表 500 万行,索引才划算
- 数据倾斜严重:比如
status = 0占 99%,status = 1占 1%,优化器可能对前者直接放弃索引 - 统计信息过期:
ANALYZE TABLE orders可强制更新表的行数、索引基数等元数据,影响优化器判断 - MySQL 版本差异:8.0 对 ICP(Index Condition Pushdown)支持更好,某些条件下会把部分 WHERE 下推到存储引擎层,而 5.7 不会
最常被忽略的一点:索引失效往往不是单点问题,而是 SQL + 参数 + 数据分布 + 统计信息 + MySQL 配置共同作用的结果。只改 SQL 或只加索引,常常治标不治本;必须用 EXPLAIN 固定参数后验证,再对比 rows 和实际扫描量,才能确认是否真解决了问题。


















