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%,说明条件区分度差,需要调整索引或查询逻辑。
