
EXPLAIN 输出里哪些字段真正影响查询性能
关键就看 type、key、rows、Extra 这四个。其他字段(比如 id、table)只是辅助定位,不直接决定快慢。
type 值从好到差大致是:const ≈ eq_ref > ref > range > index > ALL。一旦看到 ALL,基本等于全表扫描,得立刻查索引是否缺失或失效。
key 显示实际用的索引名。空值或 NULL 表示没走索引;如果显示了索引但 rows 很大,可能是索引选择性差,或者用了前导列不匹配的联合索引。
Extra 里最危险的是 Using filesort 和 Using temporary —— 排序或分组没走索引,MySQL 被迫在内存或磁盘上额外处理,QPS 上去后容易拖垮。
为什么加了索引,EXPLAIN 还显示 type=ALL
常见原因不是索引没建,而是查询写法让索引“不可用”。
- 对索引列做函数操作:
WHERE YEAR(create_time) = 2023→ 改成WHERE create_time >= '2023-01-01' AND create_time - 隐式类型转换:
user_id是INT,却写成WHERE user_id = '123'→ 字符串常量触发转换,索引失效 - LIKE 左模糊:
WHERE name LIKE '%abc'→ B+ 树无法从左开始匹配,只能扫全表 - 联合索引没用上最左前缀:
INDEX(a,b,c),但只查WHERE b = 1→ 不走索引
EXPLAIN FORMAT=JSON 比传统输出多看出什么
传统 EXPLAIN 看不到“为什么选这个索引”和“成本估算依据”,而 EXPLAIN FORMAT=JSON 会暴露优化器的决策逻辑。
重点关注 query_block 下的 cost_info(比如 query_cost)、used_tables、以及 attached_condition(下推到存储引擎的条件)。
例如发现 query_cost: 1250.3,但改写 SQL 后降到 42.7,就能确认优化有效;如果 attached_condition 为空,说明 WHERE 条件根本没下推,可能被上层临时表过滤,性能隐患很大。
EXPLAIN 的局限:它不反映真实执行时的锁、并发和缓存
EXPLAIN 只模拟“理想路径”,不体现:
- 行锁等待:
SELECT ... FOR UPDATE在高并发下可能卡住,但EXPLAIN看不出 - Buffer Pool 命中率:第一次跑慢、第二次飞快,
EXPLAIN输出一模一样 - 统计信息过期:
ANALYZE TABLE没跑过,优化器基于错误的行数估算选错索引,EXPLAIN却显得“很合理” - 子查询展开方式:
IN (SELECT ...)可能转成EXISTS或物化表,EXPLAIN不一定提前暴露这种变形
所以线上慢查,不能只看 EXPLAIN;必须结合 SHOW PROFILE、slow_query_log 中的真实耗时分布,以及 information_schema.INNODB_TRX 查阻塞源头。










