子查询或连接?

kac*_*apy 6 sql-server-2005 sql-server

在 SQL 服务器效率方面哪个更好;使用子查询或连接?

我知道不相关比相关子查询更好。但是连接呢?

使用联接使 SQL 变得更具可读性和可理解性

OUTER JOIN and check for NULLS
Run Code Online (Sandbox Code Playgroud)

但是对于数据库的性能来说是更糟还是更好?

gbn*_*gbn 6

以您的示例为例,如果 c2 是 c1 的子代(又名 c2 中的每行中的多行),则这些查询通常是不同的。这是通常的情况,除非您只有 1:1 的关系。

select c1 from t1 join t2 on c1 = c2

select c1 from t1 where c1 in (select c2 from t2)
Run Code Online (Sandbox Code Playgroud)
  • 第一个将为每场比赛分配一行
  • 第二个仅给出唯一的 c1 值。

要使它们相同,您需要在第一个上使用 DISTINCT:这不会使其更具可读性。

更进一步,第二个可以表示为

select c1 from t1
INTERSECT
select c2 from t2

select c1 from t1 where EXISTS (select * from t2 WHERE t1.c1 = t2.c2))
Run Code Online (Sandbox Code Playgroud)

即:IN、EXISTS 和 INTERSECT 给出相同的结果。

现在,由于您询问了 LEFT JOIN,我们也可以涵盖相反的情况。这里我们没有 IN、NOT EXISTS、LEFT JOIN 和 EXCEPT。

假设我们想要 t1 中的行而 t2 中没有行,其中 t2.c3 = 'foo'

select c1 from t1 left join t2 on t1.c1 = t2.c2 AND t2.c3 = 'foo'
WHERE t2.c2 IS NULL

select c1 from t1 where c1 NOT in (select c2 from t2 where t2.c3 = 'foo')

select c1 from t1
EXCEPT
select c2 from t2 where t2.c3 = 'foo'

select c1 from t1 where NOT EXISTS
        (select * from t2 WHERE t1.c1 = t2.c2 AND t2.c3 = 'foo')
Run Code Online (Sandbox Code Playgroud)

在这种情况下,只有 EXCEPT 和 NOT EXISTS总是正确的。NOT IN 将在 t2.c2 中失败,永远为 NULL。并且您需要在 LEFT JOIN 中使用 DISTINCT。

另请注意,LEFT JOIN 过滤器位于 ON 子句中。要删除它,您需要派生表或 CTE。

我还要说,鉴于查询优化器的复杂性,这些天的子查询并不重要(当然除非被滥用)

就我个人而言,我几乎总是使用 EXISTS 和 NOT EXISTS(为了清楚起见,可能是 INTERSECT 或 EXCEPT),所以我的代码是一致的,并且适用于所有情况。我不必担心将 LEFT JOIN 变成 INNER JOIN 或 NOT IN 中的 NULL。