子查询应慎用,优先JOIN替代单值关联、用EXISTS替代IN、窗口函数替代分组统计、CTE简化嵌套逻辑,并以EXPLAIN验证执行计划优化效果。

子查询写起来顺手,但用不好就拖慢整个查询。关键不是禁用它,而是知道什么时候该换、怎么换更稳更快。
能用JOIN就别硬套子查询
当子查询只用来关联另一张表的单个值(比如查部门平均工资),JOIN通常更高效。数据库能一次性走索引连接,避免反复执行子查询逻辑。
- WHERE里用子查询匹配单值 → 改成INNER JOIN或LEFT JOIN
- 子查询只查一个字段且不带聚合 → 多数情况可直接JOIN替代
- 注意驱动表顺序:小表作左表,减少循环次数
IN太多?优先试EXISTS
IN后面跟子查询,尤其结果集较大时,容易触发临时表和全量扫描。EXISTS在命中第一条就退出,对大表更友好。
- 子查询返回几十行以上,EXISTS大概率比IN快
- 确保关联字段有索引,否则EXISTS优势打折扣
- NOT IN要特别小心:只要子查询含NULL,整条结果为空;NOT EXISTS没这问题
窗口函数能干的,别让子查询扛
想算每个分组的累计值、排名、平均值……这类“同一组内横向计算”,窗口函数是专治良方。比子查询简洁,性能也高得多。
- AVG() OVER(PARTITION BY dept) 比 (SELECT AVG(...) FROM ...) 快且易读
- RANK()、ROW_NUMBER()、LAG() 都属于这类不可替代场景
- 避免在SELECT列表里反复写相同子查询来算统计值
复杂逻辑拆出来,用CTE理清楚
子查询嵌套三层以上?先别硬改,试试CTE。把中间结果命名、复用,既方便调试,也能让优化器更好规划执行路径。
- CTE不是视图,不物化数据,开销小
- 同一CTE可在主查询中多次引用,避免重复计算
- 配合WITH RECURSIVE还能处理树形结构,子查询很难做到
基本上就这些。替换不是教条,核心是看执行计划——加EXPLAIN跑一遍,对比type、rows、Extra字段,比凭经验靠谱得多。










