必须盯死type、key、rows三列:type为all表示全表扫描,key为null说明未用索引,rows接近总行数表明索引失效或选择性差。

EXPLAIN 输出里哪几列必须盯死?
看 EXPLAIN 结果不是扫一眼就完事,重点盯三列:type、key、rows。这三列直接暴露查询是否走索引、走哪个索引、扫描多少行。
-
type值是ALL?基本等于全表扫描,10 万行表查一次就得遍历全部,立刻要加索引 -
key是NULL?说明没用上任何索引,哪怕你建了索引,也可能因为 WHERE 里写了UPPER(email)或age + 1 = 25导致失效 -
rows数远大于实际返回行数(比如查 1 条却预估扫 8 万行)?统计信息可能过期,得跑ANALYZE TABLE users
为什么 type=range 还很慢?
range 看起来比 ALL 好,但真不一定快——它只表示用了索引做范围扫描,不代表高效。比如 WHERE created_at > '2020-01-01' 在千万级表上仍可能扫几十万行。
- 检查
rows值是否过大;如果大,说明索引选择性差,得换字段或加复合索引 - 确认是否覆盖查询:SELECT 的字段是否全在索引里?否则会回表,
Extra里出现Using where且没Using index就是信号 - 避免在 range 条件字段上做函数操作,
DATE(created_at) = '2023-01-01'会让索引完全失效
JSON 格式执行计划比表格更有用吗?
对简单单表查询,表格够用;但涉及 JOIN、子查询、UNION 时,EXPLAIN FORMAT=JSON 才能看清嵌套结构和各层的预估成本。
- 看
"cost_info"下的"query_cost",数值越大越耗资源 - 找
"nested_loop"或"hash_join"节点,确认连接顺序是否合理(小表驱动大表) - 留意
"filtered"字段:若远低于 100%,说明 WHERE 条件过滤效果差,可能需要调整索引顺序或拆分条件
执行计划“看着没问题”,查询还是慢怎么办?
常见陷阱是把执行计划当静态快照,忽略了运行时干扰。
- 锁等待:
SHOW PROCESSLIST查是否有State为Waiting for table metadata lock或Locked的线程 - 临时表/文件排序:
Extra出现Using temporary或Using filesort,说明内存不够或 ORDER BY 字段没索引 - 参数绑定导致计划复用错误:同一条 SQL 用不同参数执行,优化器可能复用上次低效计划,可加
/*+ RECOMPILE */(SQL Server)或清缓存(MySQL 用FLUSH TABLES)验证
执行计划只是起点,不是终点。真正卡住的地方,往往藏在 rows 预估偏差、锁状态、内存配置这些“看不见”的环节里。










