type=all不一定慢,实际性能取决于表大小、缓存状态及是否使用内存临时表;rows列比type更能反映真实代价;dependent subquery需改写为join或加索引;using temporary/filesort需检查排序字段索引覆盖;mysql与postgresql执行计划差异大,不可直接套用经验。

EXPLAIN 看不懂执行计划里的 type=ALL 是不是一定慢
不是。type=ALL 表示全表扫描,但实际快不快,得看表小不小、有没有被缓存、是否走的是内存临时表。比如 SELECT * FROM tiny_config WHERE key='app_mode' 即使 type=ALL,查 10 行也比走索引还快——因为索引还要回表、还要维护 B+ 树导航开销。
实操建议:
- 先用
EXPLAIN FORMAT=TRADITIONAL或EXPLAIN FORMAT=JSON(MySQL 5.7+)看完整结构,别只盯 type - 重点关注
rows列:它反映优化器预估的扫描行数,比 type 更直接反映代价 - 如果
rows很大但查询实际很快,可能是数据全在 buffer pool 里;反之若慢,再检查key是否为 NULL、possible_keys是否为空
嵌套子查询里 EXPLAIN 显示 select_type=DEPENDENT SUBQUERY 怎么办
这说明子查询要为外层每一行重复执行一次,是性能杀手。常见于 WHERE x IN (SELECT y FROM t2 WHERE t2.id = t1.ref_id) 这类写法。
实操建议:
- 优先改写成
JOIN:把子查询逻辑“拉平”,让优化器有机会用哈希连接或物化临时表 - 确认外层字段是否加了索引:如果
t1.ref_id没索引,DEPENDENT SUBQUERY会雪上加霜 - MySQL 8.0+ 可尝试加
/*+ NO_MERGE() */提示强制物化子查询,但需配合EXPLAIN ANALYZE验证效果
EXPLAIN 输出里 Extra 出现 Using temporary; Using filesort
这不是警告,是事实陈述:MySQL 确实建了临时表并排序了。问题在于——为什么?通常是因为 GROUP BY / ORDER BY 字段没走索引,或索引无法覆盖排序需求。
实操建议:
- 检查
ORDER BY字段是否在联合索引最左前缀上;例如ORDER BY a,b,索引(a,c,b)就无效,必须是(a,b)或(a,b,c) - 如果用了
SELECT *+ORDER BY,而索引只覆盖部分列,MySQL 仍可能放弃索引排序,改用 filesort -
Using temporary在UNION或复杂GROUP BY中难以避免,但可看rows和filtered判断是否因前置条件太松导致临时表过大
PostgreSQL 的 EXPLAIN 和 MySQL 的区别在哪,能直接套用经验吗
不能。PostgreSQL 的 EXPLAIN 默认不显示实际耗时和行数,得加 ANALYZE;而且它的 Nested Loop 不等于慢,反而是小表 join 大表时最高效的策略。
实操建议:
- MySQL 看
type和rows,PostgreSQL 看Actual Total Time和Rows Removed by Filter - PostgreSQL 的
Bitmap Heap Scan常被误读为“慢”,其实它是并发读取页后批量过滤,比顺序扫描更优 - 跨数据库调优时,别抄
FORCE INDEX这种 MySQL 专属语法,PostgreSQL 用SET enable_seqscan = off临时验证,但上线必须靠索引设计
嵌套查询的执行路径不是线性流程图,而是优化器在统计信息、内存限制、索引覆盖度之间反复权衡的结果。哪怕 EXPLAIN 看起来一样,不同版本、不同数据分布下真实行为可能差很远——所以别信截图,要自己 EXPLAIN ANALYZE 跑一遍。










