explain 是 mysql 性能分析起点,仅模拟优化器决策、不执行 sql;需重点关注 type(访问类型)、key(实际索引)、rows(预估扫描行数)和 extra(警告信号)四大字段来定位瓶颈。

Explain 是 MySQL 性能分析的起点,不是万能诊断工具,但能快速暴露查询执行中的关键瓶颈。它不运行 SQL,只模拟优化器决策过程,因此结果反映的是“计划”,而非实际耗时——但这个计划往往直接决定实际表现。
看懂 type 字段:访问方式决定效率上限
type 是执行计划里最敏感的性能指标,它告诉你 MySQL 怎么读取数据。从好到差大致是:const ≈ eq_ref > ref > range > index > ALL。重点盯住是否出现 ALL(全表扫描)或 index(全索引扫描),这两类通常意味着低效。
- type = const:用主键或唯一索引做等值查询,命中单行,最快
- type = ref:用非唯一索引查多个匹配行,常见且健康
- type = range:范围查询(如 >、BETWEEN、IN),只要范围不过大,可接受
- type = ALL:没走任何索引,逐行扫描,数据量一上万就明显拖慢
确认 key 和 rows:索引是否真被用上?
key 显示实际生效的索引名,key 为 NULL 就等于没走索引;rows 是优化器预估要检查的行数,不是返回行数。这个值越接近实际结果集大小越好,如果 rows 是几万而实际只返回几十行,说明过滤能力弱,可能缺索引或索引未覆盖查询条件。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- possible_keys 有值但 key 为 NULL:索引存在,但优化器认为不划算,常因统计信息过期或条件写法导致失效(比如对字段加函数)
- key_len 值偏小:复合索引只用了最左前缀的一部分,比如 (a,b,c) 索引,查询只含 a 和 c,b 被跳过,key_len 只反映 a 的长度
- rows 远大于实际返回行数:WHERE 条件过滤性差,考虑补充索引或重写条件(如避免 LIKE '%xxx')
警惕 Extra 中的警告信号
Extra 不是补充说明,而是性能红灯。它揭示了优化器在执行计划中不得不做的“额外工作”,每一条都对应潜在优化点。
- Using filesort:ORDER BY 无法利用索引排序,需额外内存/磁盘排序。解决办法是让 ORDER BY 字段包含在索引末尾,且顺序一致
- Using temporary:GROUP BY、DISTINCT 或某些 JOIN 触发临时表。尽量让 GROUP BY 字段落在索引最左部分,或改用覆盖索引减少回表
- Using index:好消息,表示走了覆盖索引,无需回表查数据行
- Using where:正常情况,表示存储引擎返回后还需服务器层二次过滤;但如果配合 type=ALL,说明连基础索引都没用上
结合 id 和 select_type 判断查询结构复杂度
id 和 select_type 一起看,能还原出 SQL 的真实执行逻辑。简单查询 id 全是 1;子查询或 UNION 会让 id 出现不同数值或特殊类型。
- id 相同:这些步骤属于同一层级,按从上到下顺序执行
- id 越大,越先执行(注意:不是“优先级高”,而是依赖关系倒置,比如派生表必须先算出来)
- select_type = DERIVED 或 SUBQUERY:说明有子查询,尤其是嵌套在 FROM 或 WHERE 里的,容易成为性能黑洞
- select_type = UNION RESULT + table = NULL:这是合并结果的收口操作,本身不查表,但前面的 UNION 各分支可能各自低效










