news 2026/6/5 18:59:00

SQL改写实战(续):子查询vs JOIN的深层原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SQL改写实战(续):子查询vs JOIN的深层原理

关键词​:子查询;JOIN;半连接;物化;查询优化器;SQL改写


大家好,我是小耶,写功课只是为了我踩过的坑,你们别再踩了!

上周我们讲了COUNT进阶,这周回到SQL改写的一个经典话题:子查询和JOIN,到底哪个更快?网上有很多说法,“能用JOIN就别用子查询”,但我在实际工作中见过反例——有时候子查询反而更快。今天我们从原理到实测,彻底讲透这件事。

一、子查询与JOIN的本质差异

  • JOIN​:你把两个朋友圈(表A和表B)的所有人直接配对,找出共同认识的人。相当于先做笛卡尔积再过滤,但优化器会通过索引、哈希等算法优化。
  • 子查询​:你先从表B中找出符合条件的人(子查询结果),然后拿着这个名单去表A中找对应的人。相当于分两步走。

从关系代数角度看,一个子查询可以改写为JOIN的前提是:子查询的结果集可以被“物化”为一个临时表,然后再与原表进行连接。但优化器是否会这样做,取决于代价估算。

二、优化器如何处理子查询

MySQL优化器对子查询的处理策略主要有以下几种:

策略机制适用场景实例
半连接(semi-join)将IN/EXISTS子查询转换为类似JOIN的操作,但只返回外表的行子查询不复杂,结果集不大SELECT * FROM t1 WHERE col IN (SELECT col FROM t2)
物化先执行子查询,将结果存入临时表(带索引),再与外表连接子查询结果集较小同上半连接
EXISTS改写对每一行外表,执行子查询判断是否存在子查询结果集非常大,且外表小SELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.id=t1.id)
相关子查询子查询依赖外表的当前行,每行执行一次无法改写为JOIN时SELECT * FROM t1 WHERE col = (SELECT MAX(col) FROM t2 WHERE t2.id=t1.id)

重要​:MySQL从5.6版本开始引入了半连接优化,很多IN子查询会自动转为半连接,性能与JOIN相当。所以“子查询慢”的说法在MySQL 5.6+已经不成立了。

三、实测对比:子查询 vs JOIN

环境:MySQL 8.0.32,8C32G,表t1(1000万行),表t2(500万行),都有索引。

场景1:IN子查询(可转为半连接)

-- 子查询 SELECT * FROM t1 WHERE id IN (SELECT t1_id FROM t2 WHERE status = 1); -- JOIN写法 SELECT t1.* FROM t1 JOIN t2 ON t1.id = t2.t1_id WHERE t2.status = 1;

实测结果:两者执行时间都在1.2-1.5秒之间,几乎无差别。查看执行计划,子查询被优化为半连接,实际执行相同的操作。

场景2:相关子查询(无法转为JOIN)

-- 子查询(每行执行一次) SELECT * FROM t1 WHERE amount > (SELECT AVG(amount) FROM t2 WHERE t2.cat_id = t1.cat_id);

这种相关子查询无法直接转为JOIN,改写JOIN需要先聚合再连接:

SELECT t1.* FROM t1 JOIN (SELECT cat_id, AVG(amount) as avg_amount FROM t2 GROUP BY cat_id) t2_avg ON t1.cat_id = t2_avg.cat_id AND t1.amount > t2_avg.avg_amount;

实测:子查询耗时38秒(每行执行一次子查询,1000万次),JOIN+聚合耗时0.9秒。此时JOIN完胜。

结论​:能否优化的关键不在于“子查询还是JOIN”,而在于子查询是否可以被优化器转为半连接或物化。可转换的,性能相近;不可转换的(尤其是相关子查询),必须改写。

四、什么时候子查询可能比JOIN更快?

  • 子查询结果集极小​:物化临时表比JOIN的哈希表构建更快。
  • 外表极大,子查询高度过滤​:先执行子查询过滤掉大部分数据,再与外表连接,减少扫描量。
  • 子查询使用了覆盖索引​:子查询直接从索引返回数据,避免回表。

示例:SELECT * FROM t1 WHERE id IN (SELECT id FROM t2 WHERE status = 1 LIMIT 10),子查询只返回10个id,物化成本极低,可能比JOIN全表扫描快。

五、系统化的改写决策

子查询类型优化器处理是否建议改写改写方法
IN (SELECT ...)子查询不依赖外表半连接/物化通常不需要可保持原样
EXISTS (SELECT ...)外表小、子查询大外层循环可改写为JOIN改为JOININ
相关子查询(WHERE条件依赖外表)每行执行一次强烈建议改为JOIN+聚合
NOT IN子查询可能产生全表扫描建议改为NOT EXISTSLEFT JOIN ... IS NULL
IN子查询结果集极大物化开销大可考虑改写为EXISTS改为EXISTS

特别注意​:NOT IN子查询在子查询结果包含NULL时,结果永远是空(因为NOT IN (NULL, 1, 2)的语义),这是SQL标准行为。建议改用NOT EXISTSLEFT JOIN,避免逻辑错误。

六、实战案例:优化一个慢查询

原SQL(耗时26秒):

SELECT * FROM orders o WHERE o.status = 'PENDING' AND o.order_date > '2026-01-01' AND o.user_id IN (SELECT user_id FROM users WHERE register_date < '2025-01-01');

执行计划显示:子查询被物化(用了索引),但物化表有200万行,然后外层表扫描后与物化表半连接,效率尚可,但仍有优化空间。

改写为JOIN(耗时18秒):

SELECT o.* FROM orders o JOIN users u ON o.user_id = u.user_id WHERE o.status = 'PENDING' AND o.order_date > '2026-01-01' AND u.register_date < '2025-01-01';

为什么只快了一点?因为orders表本身有1000万行,索引过滤后仍有300万行,JOIN也需要扫描这些行。进一步优化:在orders(user_id, status, order_date)上建复合索引,并将查询改为覆盖索引,再回表取其他列,最终降到6秒。

启示​:不要只纠结子查询vs JOIN,索引设计往往影响更大。

七、总结

子查询和JOIN孰优孰劣,没有绝对答案,取决于优化器版本、数据分布、索引设计、子查询类型。掌握优化器处理子查询的机制(半连接、物化、相关),结合EXPLAIN分析执行计划,才能做出正确的改写决策。盲目相信“永远用JOIN”可能会错过子查询在某些场景下的优势。

小耶在手,SQL 不愁

还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~

参考文献

  1. MySQL官方文档:《Subquery Optimization》
  2. 《高性能MySQL》第4版,第9章:查询优化
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/5 18:55:58

别再瞎写C代码了!手把手教你用PC-Lint/Helix QAC检查Misra-C 2012规范

实战指南&#xff1a;用静态分析工具高效检查Misra-C 2012规范在嵌入式开发领域&#xff0c;代码质量直接关系到产品的可靠性和安全性。Misra-C规范作为行业公认的C语言编码标准&#xff0c;已经成为汽车电子、航空航天等高可靠性系统的必备要求。但对于大多数开发者来说&#…

作者头像 李华
网站建设 2026/6/5 18:52:56

避开STM32H7的FDCAN内存重叠坑:一份给CubeMX用户的配置检查清单

STM32H7双FDCAN配置避坑指南&#xff1a;CubeMX用户必须掌握的Message RAM规划策略 当你在CubeMX中勾选第二个FDCAN接口时&#xff0c;是否注意到那个默认为0的Message RAM Offset参数&#xff1f;这个看似不起眼的数字&#xff0c;很可能成为项目后期通信故障的元凶。本文将带…

作者头像 李华
网站建设 2026/6/5 18:51:55

Windows资源编辑终极指南:rcedit命令行工具完整教程

Windows资源编辑终极指南&#xff1a;rcedit命令行工具完整教程 【免费下载链接】rcedit Command line tool to edit resources of exe 项目地址: https://gitcode.com/gh_mirrors/rc/rcedit 想要轻松修改Windows可执行文件的资源信息吗&#xff1f;rcedit是一款功能强大…

作者头像 李华
网站建设 2026/6/5 18:50:59

2026年最新实测:用录音转文字神器改善亲子沟通,效率翻倍!

作为一位常年研究办公效率工具的测评师&#xff0c;我本以为“录音转文字”这类工具只属于职场——会议记录、课程笔记、访谈整理。但直到我朋友老张的经历&#xff0c;让我彻底改观。老张是个典型的技术爸爸&#xff0c;平时工作忙&#xff0c;和读初中的儿子小宇沟通越来越少…

作者头像 李华