反连接与半连接(NOT EXISTS)
使用 EXISTS/NOT EXISTS 查找“ A 中在 B 中没有匹配项的行”(反连接)和“ A 中在 B 中至少有一个匹配项的行”(半连接)。
反连接与半连接(NOT EXISTS) 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。
半连接:“至少存在一个匹配项”
返回 A 中至少有一行与 B 匹配的行——但只返回 A 的列。SQL 通过 EXISTS 或 IN 实现半连接。
EXISTS 半连接
至少下过一个订单的用户:
SELECT u.* FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);IN 半连接
结果相同,但写法不同:
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);为什么 EXISTS 通常更快
EXISTS 会提前结束:每个外层行找到第一个匹配项后就停止。IN 可能会将整个内部集合物化。现代规划器通常会将两者优化为相同的执行计划,但对于巨大的内部集合,EXISTS 是更稳妥的选择。
反连接:“没有匹配项”
从未下过订单的用户——有三种惯用写法:
-- NOT EXISTS (preferred):
SELECT u.* FROM users u
WHERE NOT EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);
-- LEFT JOIN ... IS NULL:
SELECT u.* FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.id IS NULL;
-- NOT IN (risky with NULLs):
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders);为什么 NOT IN 有风险
如果内部子查询包含 NULL,NOT IN 会返回 NULL,而 WHERE 会丢弃谓词为 NULL 的行。结果是零行。NOT EXISTS 没有这个问题。
规划器优化
现代 PostgreSQL 能识别 EXISTS 和 NOT EXISTS 形式的半连接/反连接模式,并可能使用哈希连接执行:
EXPLAIN ANALYZE
SELECT u.* FROM users u
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);
-- → Hash Anti Join多列反连接
使用复合键:
SELECT * FROM order_items oi
WHERE NOT EXISTS (
SELECT 1 FROM shipments s
WHERE s.order_id = oi.order_id
AND s.line_no = oi.line_no
);带附加谓词的 EXISTS 半连接
向内部子查询添加筛选条件:
SELECT u.* FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.user_id = u.id
AND o.status = 'paid'
AND o.created_at >= NOW() - INTERVAL '30 days'
);为关联列创建索引
对于 EXISTS 和 NOT EXISTS,内部子查询都会根据外层行的键进行筛选。如果该键没有索引,就会针对每个外层行执行一次扫描:
CREATE INDEX orders_user_id_idx ON orders(user_id);何时使用 LEFT JOIN ... IS NULL
如果仪表板还需要未匹配一侧的列,LEFT JOIN 写法会很自然。对于纯粹的反连接语义,NOT EXISTS 更清晰。
超越 SQL:布隆过滤器
对于巨大的反连接,可以先使用布隆过滤器进行预筛选。PostgreSQL 通过 bloom 扩展支持 bloom 索引。
回顾
半连接 =“有匹配项”;反连接 =“没有匹配项”。
- 半连接使用 EXISTS
- 反连接使用 NOT EXISTS(对 NULL 安全)
- 为关联列创建索引
- 除非内部集合不可能包含 NULL,否则避免使用 NOT IN
快速检查
您想找出从未下过订单的用户。哪种 SQL 写法最安全、最符合惯例?
用 AI 导师学习 SQL — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 46
- 课程
- 183
常见问题解答
「反连接与半连接(NOT EXISTS)」课时是免费的吗?
是的 — 「反连接与半连接(NOT EXISTS)」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。
「反连接与半连接(NOT EXISTS)」这节课中我会学到什么?
使用 EXISTS/NOT EXISTS 查找“ A 中在 B 中没有匹配项的行”(反连接)和“ A 中在 B 中至少有一个匹配项的行”(半连接)。 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 SQL Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「反连接与半连接(NOT EXISTS)」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 SQL Academy 课中编写并运行代码吗?
能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 交叉连接与笛卡尔积
- 横向连接(LATERAL JOIN)
- 反连接与半连接(NOT EXISTS)
- 多表连接性能调优