EXPLAIN重点关注type、key、rows、Extra四列:type为ALL需优化,key为空说明未用索引,rows是预估扫描行数,Extra含Using filesort或temporary是性能红灯。

EXPLAIN 输出字段怎么看
执行 EXPLAIN SELECT ... 后,重点关注 type、key、rows、Extra 这四列。它们直接反映查询是否走索引、扫描范围多大、有没有临时表或文件排序。
-
type值为ALL表示全表扫描,通常要优化;range或ref是较健康的状态 -
key为空说明没用上索引,即使有索引也可能因隐式类型转换、函数包裹(如WHERE YEAR(created_at) = 2023)而失效 -
rows是 MySQL 预估的扫描行数,不是结果集大小;如果远大于实际返回行数,说明索引选择不佳或统计信息过期(可用ANALYZE TABLE更新) -
Extra出现Using filesort或Using temporary是性能红灯,尤其在大表分页(LIMIT 10000,20)时极易触发
联合索引顺序为什么不能乱
MySQL 的联合索引遵循最左前缀匹配原则,INDEX (a, b, c) 能命中 WHERE a = 1 AND b = 2,但对 WHERE b = 2 AND c = 3 完全无效。
- 查询条件中跳过首字段(如只用
b或c),索引就无法利用 - 范围查询(
>、BETWEEN、LIKE 'abc%')之后的字段不再用于索引查找,例如WHERE a = 1 AND b > 10 AND c = 5中,c不会走索引查找,仅用于过滤 - 排序字段也要纳入联合索引覆盖,否则容易触发
Using filesort;比如ORDER BY a, b,索引应建为(a, b)而非单独(a)或(b)
为什么有时候加了索引却没走
索引存在不等于被使用。MySQL 优化器会根据成本估算决定是否走索引,常见“有索引却不走”的原因包括:
- 查询返回大量数据(如超过全表 20% 行数),优化器可能认为全表扫描比回表更快
- 字段存在隐式类型转换:比如
user_id是INT,但写成WHERE user_id = '123',会触发字符串转数字,导致索引失效 - 对索引字段使用函数或表达式:
WHERE DATE(create_time) = '2024-01-01'→ 改为WHERE create_time >= '2024-01-01' AND create_time - 统计信息陈旧:执行
ANALYZE TABLE table_name可强制更新,影响优化器决策
EXPLAIN FORMAT=JSON 有什么用
普通 EXPLAIN 只显示顶层执行计划,而 EXPLAIN FORMAT=JSON 提供嵌套结构,能看清子查询展开方式、索引合并(index_merge)、条件下推(attached_condition)等细节,适合复杂查询排障。
EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE status = 1);
输出中注意 "select_subquery" 和 "attached_condition" 字段,它们揭示子查询是否被重写为 JOIN、过滤条件是否下推到物化表——这些直接影响执行效率。很多看似“应该走索引”的慢查,真正瓶颈藏在 JSON 输出的 "filtered" 值里(表示该节点过滤后剩余行数比例),若长期低于 10%,说明条件区分度差,需要调整索引或查询逻辑。










