例:
php
SELECT * FROM cmf_fast_register r WHERE r.icp_status = '0' AND EXISTS ( SELECT * FROM cmf_icp i WHERE (i.app_id = r.app_id) )
一、结论:里面包含子查询(相关子查询)
整条 SQL 分为两部分:
- 外层主查询:
SELECT * FROM cmf_fast_register r WHERE ... - 内层
EXISTS(...)括号里的一整段,就是子查询
sql
-- 这一段就是子查询
SELECT * FROM `cmf_icp` `i` WHERE ( i.app_id = r.app_id )
二、什么是「相关子查询」
它不是普通子查询,是相关子查询 :
子查询里用到了外层表的别名 r(r.app_id),子查询不能独立执行,必须依赖外层每一行的数据。
执行逻辑拆解:
- 数据库先遍历外层
cmf_fast_register每一条记录 r - 拿当前这条 r 的
app_id丢进内层子查询 - 去
cmf_icp匹配有没有i.app_id = 当前r.app_id的数据 - EXISTS 只判断「有没有匹配结果」,有就保留这条 r,没有就过滤掉
- 再叠加条件
r.icp_status = 0双重筛选
三、EXISTS 的特点(对比 IN / JOIN)
-
只判断存在,不返回数据
你里面写SELECT *其实没用,推荐改成SELECT 1,性能更好,逻辑不变:sqlEXISTS ( SELECT 1 FROM `cmf_icp` `i` WHERE i.app_id = r.app_id ) -
不会产生重复行
即使一条 r 对应几十条 icp,EXISTS 只标记"存在",外层 r 只会输出一次,完美解决你之前一对多 JOIN 重复数据的问题。 -
匹配到第一条 icp 就立刻停止检索,大数据量性能优于 INNER JOIN。
四、整条 SQL 语义翻译
查询所有满足两个条件的 cmf_fast_register 数据:
- 自身字段
icp_status = 0 - 在
cmf_icp表中存在同 app_id 的关联记录
五、补充区分概念
- 子查询 :写在
()内部、嵌套在主查询里的查询语句; - 相关子查询:子查询引用了外层查询的表/字段;
- 普通子查询(非相关):不依赖外层,可以单独执行,例如
WHERE app_id IN (SELECT app_id FROM cmf_icp)。