type字段表示mysql查找行的访问类型,性能从差到好依次为all、index、range、ref、eq_ref、const、system、null;all为全表扫描,index为全索引扫描,二者均为全量扫描但io路径不同。
navicat 执行计划里每个节点不是“步骤清单”,而是 mysql 优化器对某一部分数据访问方式的建模表达——它告诉你「这一行计划」在查哪张表、用什么方式找数据、是否依赖外部结果,而不是“先做a再做b”的线性流程。
type 字段决定实际扫描效率,不是有没有索引
看到 type 是 ref 就以为没问题?错。它只说明用了非唯一索引等值匹配,但可能返回 5 万行;而 range 看似不如 ref,查时间范围时反而是合理且高效的选择。
-
ALL和index都是全量扫描:ALL扫数据页,index扫索引页——后者 IO 少,但 CPU 过滤压力大,实际性能可能更差 -
eq_ref出现在 JOIN 中,要求被驱动表的连接字段必须是主键或唯一索引,否则会退化成ref -
const不代表“常量表达式”,而是主键/唯一索引精确命中单行(如WHERE id = 123),统计信息过期时也可能误判为ref - 联合索引顺序错位(比如 WHERE a = ? AND b = ?,却建了
(b, a)),type仍是ref,但key_len明显偏短,实际只用到第一个字段
select_type 揭示 SQL 结构本质,别被表名骗了
select_type 是判断语句是否“表面简单、背后复杂”的第一眼指标。很多慢查询根本不是因为 JOIN 多,而是隐含了子查询或 UNION 导致临时表生成。
-
SIMPLE:真·单层查询,哪怕多表JOIN也没问题;但一旦加了IN (SELECT ...),外层就变成PRIMARY -
DERIVED:FROM 里的子查询,MySQL 必须物化成临时表,即使只查一行也会触发磁盘或内存临时表开销 -
UNION RESULT这一行永远存在——只要用了UNION或UNION ALL,就说明结果集要从临时表里捞,高并发下容易成为瓶颈 -
DEPENDENT SUBQUERY最危险:对外层每一行都执行一次子查询,rows 值 × 子查询成本 = 真实爆炸点
颜色只是估算权重,不等于真实耗时
Navicat 17 默认的红→绿渐变色,标的是优化器预估成本占比,不是你看到的秒级延迟。深红色节点可能实际毫秒级完成,而浅黄色的 index 扫描在大数据量下反而卡住连接。
- 必须勾选
Show Actual Execution Stats(右键执行计划图 → 刷新执行统计),否则所有颜色都不可信 - MySQL 连接需确认
performance_schema已开启,且连接字符串带?useSSL=false&allowPublicKeyRetrieval=true,否则拿不到完整运行时字段 - PostgreSQL 用户注意:
Nested Loop + Materialize组合标红,大概率是子查询未内联,可试加/*+ SET(enable_material OFF) */提示 - 若
Actual Total Time远小于Planning Time,优先检查统计信息是否陈旧(ANALYZE TABLE)或work_mem是否不足
真正容易被忽略的是 type = index:它看起来“走了索引”,实则和 ALL 一样扫全量,只是没读数据行。只要看到它,第一反应不是加索引,而是问自己——WHERE 条件到底有没有真正用上这个索引?











