IN与大型行集的JOIN

mac*_*ojw 28 sql performance join sql-server-2005

我想要在主表位于另一个表中的表中选择行.我不确定我是否应该在SQL Server 2005中使用JOIN或IN运算符.这两个SQL查询与大数据集(即数百万行)之间是否存在显着的性能差异?

SELECT *
FROM a
WHERE a.c IN (SELECT d FROM b)

SELECT a.*
FROM a JOIN b ON a.c = b.d
Run Code Online (Sandbox Code Playgroud)

Qua*_*noi 30

更新:

我的博客中的这篇文章总结了我的答案和我对另一个答案的评论,并显示了实际的执行计划:


SELECT  *
FROM    a
WHERE   a.c IN (SELECT d FROM b)

SELECT  a.*
FROM    a
JOIN    b
ON      a.c = b.d
Run Code Online (Sandbox Code Playgroud)

这些查询不等同.如果您的表b不是密钥保留(即值b.d不唯一),它们可以产生不同的结果.

第一个查询的等效内容如下:

SELECT  a.*
FROM    a
JOIN    (
        SELECT  DISTINCT d
        FROM    b
        ) bo
ON      a.c = bo.d
Run Code Online (Sandbox Code Playgroud)

如果b.dUNIQUE并且标记为(带有UNIQUE INDEXUNIQUE CONSTRAINT),那么这些查询是相同的,并且很可能将使用相同的计划,因为SQL Server它足够聪明以考虑到这一点.

SQL Server 可以使用以下方法之一来运行此查询:

  • 如果有一个索引a.c,dis UNIQUEb相对较小a,那么条件会传播到子查询中并使用plain INNER JOIN(带有b前导)

  • 如果有索引b.dd不是UNIQUE,则该条件也会传播并被LEFT SEMI JOIN使用.它也可以用于上述条件.

  • 如果有两个指标b.d,并a.c和他们是大,那么MERGE SEMI JOIN使用

  • 如果任何表上都没有索引,则构建bHASH SEMI JOIN使用哈希表.

这些方法都不是每次都重新评估整个子查询.

有关其工作原理的详细信息,请参阅我的博客中的此条目:

所有RDBMS四巨头都有链接.


gbn*_*gbn 5

都不是.使用ANSI-92 JOIN:

SELECT a.*
FROM a JOIN b a.c = b.d
Run Code Online (Sandbox Code Playgroud)

但是,它最好作为一个EXISTS

SELECT a.*
FROM a
WHERE EXISTS (SELECT * FROM b WHERE a.c = b.d)
Run Code Online (Sandbox Code Playgroud)

这将删除可能由JOIN生成的重复项,但如果不是更快则运行速度相同


The*_*des 5

根据 49,000,000 行表的经验,我建议使用 LEFT OUTER JOIN。使用 IN 或 EXISTS 需要 5 分钟才能完成,而 LEFT OUTER JOIN 在 1 秒内完成。

SELECT a.*
FROM a LEFT OUTER JOIN b ON a.c = b.d
WHERE b.d is not null -- Given b.d is a primary Key with index
Run Code Online (Sandbox Code Playgroud)

实际上,在我的查询中,我在 9 个表中执行此操作。