Mysql--基础知识点--94.1--嵌套子查询转关联查询

什么是嵌套子查询?为什么要改成关联查询?

嵌套子查询(Non-correlated subquery)是指子查询独立于外层查询,不引用外层的列。它先执行子查询得到结果集,然后外层查询利用这个结果集进行过滤或计算。

关联子查询(Correlated subquery)是指子查询引用了外层查询的列,对外层每一行都要执行一次子查询(通常可以利用索引快速判断)。

在某些场景下,将嵌套子查询改写成关联查询 (如 EXISTSJOIN)可以大幅提升性能,避免子查询产生巨大的中间结果集,或者避免 NULL 带来的逻辑陷阱。


典型改写场景:INEXISTS

原始嵌套子查询(使用 IN

sql 复制代码
-- 找出所有下过至少一单的客户
SELECT * FROM customers 
WHERE customer_id IN (
    SELECT customer_id FROM orders   -- 子查询独立,不依赖外层
);

执行逻辑

  1. 先完整执行子查询:从 orders 表中取出所有 customer_id,可能几十万行。
  2. 将结果集去重并构建哈希表。
  3. customers 每一行检查 customer_id 是否在哈希表中。

问题 :如果 orders 表非常大(几百万行),子查询结果集巨大,会消耗大量内存和 I/O。

改写为关联查询(使用 EXISTS

sql 复制代码
SELECT * FROM customers c
WHERE EXISTS (
    SELECT 1 FROM orders o 
    WHERE o.customer_id = c.customer_id   -- 关联条件
);

执行逻辑(实际优化器会做半连接):

  1. 遍历 customers 表(假设只有几千行)。
  2. 对每个客户,在 orders 表的索引上快速查找是否存在该客户的订单,找到一行就立即返回 TRUE,不再继续扫描。
  3. 整个过程无需物化庞大的订单 ID 集合。

优势

  • 外表小、内表大 时,EXISTS 通常远快于 IN
  • 避免了大结果集的物化,内存压力小。
  • 可以利用 orders.customer_id 上的索引。

另一种改写:嵌套子查询 → JOIN(关联查询)

sql 复制代码
-- 同样查询有订单的客户,使用 JOIN(注意去重)
SELECT DISTINCT c.* 
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id;

注意JOIN 可能导致客户重复(一个客户有多笔订单),所以需要 DISTINCT。如果 customers.customer_id 是主键,DISTINCT 的开销通常可接受。

性能特点

  • 数据库优化器可能将 INEXISTS 转换为类似的 JOIN 执行计划。
  • 但显式 JOIN 有时更灵活,可以同时获取订单表的其他字段。

什么时候不应该改写?

  • 子查询结果集很小 (如几十行)且不经常执行:IN 写法更直观,性能差异可忽略。
  • 需要判断 NOT IN 且子查询无 NULL :但最好还是用 NOT EXISTSLEFT JOIN 避免 NULL 陷阱。
  • 子查询是标量查询 (返回单个值),例如 SELECT ... WHERE salary > (SELECT AVG(salary) FROM employees),这种无法简单改成关联查询,因为子查询只需执行一次。

总结对照表

写法 子查询类型 执行次数 适用场景
IN (SELECT ...) 嵌套(非关联) 子查询执行1次 子查询结果集小,且外表大
EXISTS (SELECT ... WHERE 关联) 关联 外表每行执行1次(但可提前终止) 外表小,内表大,且内表有索引
JOIN ... ON 关联 关联 一次连接操作 需要同时获取两表数据,注意去重

核心建议

  • 默认优先考虑语义清晰 ,但遇到性能问题时,把嵌套子查询(特别是 INNOT IN)改写成关联查询(EXISTSJOIN)是非常有效的优化手段。
  • 使用 EXPLAIN 观察执行计划,确认数据库是否自动做了优化。
相关推荐
大师兄666814 分钟前
HarmonyOS7 数据持久化 relationalStore:数据库实战
数据库·arkui·实战案例·harmonyos7
冰茶丿26 分钟前
状态机在嵌入式系统中的应用:不只是switch-case这么简单
数据库·嵌入式硬件·mongodb
AIHR数智引擎27 分钟前
15%对撞40%:WEF白皮书里的AI组织隐忧
数据库·人工智能·经验分享·职场和发展·aihr
卓怡学长34 分钟前
w261springboot基于web学校课程管理系统
java·数据库·spring boot·spring·intellij-idea
嘉泰姆半导体官方36 分钟前
CXAR41337C 双通道数字音频功放 | 2×20W | EQ+DRC | I²S | MCLK-Less - 嘉泰姆电子
前端·javascript·数据库
不坑老师1 小时前
怎么在Word中制作汉字书写笔顺——不坑盒子汉字笔顺步骤在小学低段识字教学中的应用
前端·数据库·人工智能·word·excel·office
苍狼唤1 小时前
SQL+C# 增删改查(练习)
数据库·sql·c#
2301_800256111 小时前
第七章 空间存储与索引 知识点梳理-2
数据库·sql·oracle
草莓熊Lotso2 小时前
【Redis 初阶】 从分布式演进背景到环境搭建全解析
数据库·人工智能·redis·分布式·缓存
倔强的石头_2 小时前
优化器为什么敢把你写的 LEFT JOIN 悄悄改掉?-国产化金仓 KES 优化器设计思路拆解
数据库