是否有任何 objective 理由更喜欢一种特定形式的左反半连接?

Is there any objective reason to prefer a particular form of left anti-semi join?

我见过很多不同形式的左反半连接。请允许我列出并命名每一个想到的。以下查询旨在 return 每个 ROSTER_ID 未被任何员工使用且谁是该花名册的所有者。

--1) NOT EXISTS, with a particular column selected in the subquery
SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
WHERE NOT EXISTS (SELECT EMP_ID FROM EMPLOYEES WHERE EMP_ID = ROSTERS.EMP_ID)
--2) NOT EXISTS, with a particular column selected in the subquery and TOP (1) used
SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
WHERE NOT EXISTS (SELECT TOP (1) EMP_ID FROM EMPLOYEES WHERE EMP_ID = ROSTERS.EMP_ID)
--3) NOT EXISTS, with all data selected in the subquery
SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
WHERE NOT EXISTS (SELECT * FROM EMPLOYEES WHERE EMP_ID = ROSTERS.EMP_ID)
--4) NOT EXISTS, with all columns selected in the subquery and TOP (1) used
SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
WHERE NOT EXISTS (SELECT TOP (1) * FROM EMPLOYEES WHERE EMP_ID = ROSTERS.EMP_ID)
--5) NOT EXISTS, but just use SELECT 1
SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
WHERE NOT EXISTS (SELECT 1 FROM EMPLOYEES WHERE EMP_ID = ROSTERS.EMP_ID)
--6) NOT IN
SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
WHERE EMP_ID NOT IN (SELECT EMP_ID FROM EMPLOYEES)
--7) LEFT JOIN
SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
LEFT OUTER JOIN EMPLOYEES
ON EMPLOYEES.EMP_ID = ROSTERS.EMP_ID
WHERE EMPLOYEES.EMP_ID IS NULL

我的问题是:是否有任何 objective 原因 - 例如性能、向后兼容性、可移植性、NULL 处理、易于测试、可扩展性等 - 更喜欢执行左反半连接的任何特定方式? 我也有兴趣听听主观原因,例如风格问题或清晰度,但只包括它们将是一个无法回答的问题。

我自己的研究仅指出以下几点,但都很薄弱,而且可能是主观的:

没有,除了不吸

Aaron 的文章已经充满了丰富的信息,您已经发现了将 NOT IN 与 NULLS 结合使用的危险。

我唯一可以补充的是,我没有注意到讨论的是,当使用 (not) exists 时,FROM 之前的东西,如 select columnselect top 1 * 是如何本质上是垃圾。我什至向 sql 服务器发布了一条建议,建议使用 (anti) semi join table2 on <join condition>.

的替代语法

EXISTS, NOT EXISTS return boolean TRUE/FALSE depending.The Select columns mention in EXISTS subquery do not matter,它只根据 where cluase

检查它是否存在

例如,

SELECT ROSTER_ID, ROSTER_OWNER
FROM ROSTERS
WHERE NOT EXISTS (SELECT 1/0 FROM EMPLOYEES WHERE EMP_ID = ROSTERS.EMP_ID)

在上面的通知中 1/0 不会抛出错误,这是什么意思?

所以你的 1),2),3),4),5) 在性能和结果上都是一样的。

LEFT JOIN :当您需要结果集中的 LEFT JOIN table 列时使用。

我不认为任何答案都涵盖了所有内容,因此我尝试将所有答案和评论放在一起:

  • 示例1到5,即EXISTS示例,都是一样的。这不容易证明(您可能会发现 KumarHarsh 的示例很有说服力)并且依赖于您对优化器的信任。
  • 不要使用示例 #6,即 IN。你不能相信它 NULLs.
  • 示例 #7,即 LEFT JOIN,如果您将其用于普通(即非 anti)半连接,则可以复制结果。还有人怀疑优化器将如何处理它(参见下面的 link)。主观上,它需要看起来更多的打字,并且不太擅长传达您的意图。总的来说,最好避免。

总之,使用EXISTS。使用 TOP 的示例 #2 和 #4 毫无意义,因此您最好避免使用它们。至于是否应该使用示例#1、#3 或#5,这只是个人喜好问题。我认为 #5 最清楚地传达了意图,但这完全是一个见仁见智的问题。

This very helpful article 也建议 OUTER APPLY,但我认为没有人认真对待它。