我很好奇以下哪个会更有效?

我一直对使用IN持谨慎态度,因为我相信SQL Server会将结果集变成一个很大的IF语句。对于较大的结果集,这可能会导致性能下降。对于较小的结果集,我不确定哪一个都更好。对于较大的结果集,EXISTS效率更高吗?

WHERE EXISTS (SELECT * FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)


vs.

WHERE bx.BoxID IN (SELECT BoxID FROM Base WHERE [Rank = 2])


评论

找出答案的最佳方法是尝试一下并进行一些测量。
为此必须有大量的重复...

@marc_s-大概是这样,但是当我需要仔细阅读有关该主题的所有帖子并找到适合我的情况时,我对问题有四个答案。

仅供参考,如果您想要最高效的方法,则可以在存在的位置从Base中选择1,因为您实际上并不关心结果,只是实际上存在一行。

@marc_s真的很可悲,因为我确实花时间浏览这些帖子,以便不向stackoverflow添加更多垃圾。我不需要量身定制的答案即可完成工作。那就是那种将Gazillion重复项添加到仅少数具有良好答案的地方的想法

#1 楼

EXISTS会更快,因为一旦引擎找到了命中点,它就会退出,因为条件已经证明是正确的。

使用IN,它将在进一步处理之前从子查询中收集所有结果。

评论


那是个很好的观点。 IN语句要求SQL Server生成一个完整的结果集,然后创建我认为的大IF语句。

–兰迪·明德
2010-1-14的16:04

这曾经是正确的,但在当前版本(至少2008年)中,优化器更加智能……它实际上像INISTS()一样对待IN()。

–亚伦·伯特兰(Aaron Bertrand)
2010-1-14的16:51

@Aaron-是的,通常优化器会在内部产生更好的计划。但是,在更复杂的情况下,依赖内部快捷方式可能是有害的。

– Scott Coates
2011年5月26日下午5:43

这是完全错误的。那是在2010年,现在仍然如此。

–马格努斯
16年5月23日在19:54

IN和EXISTS具有完全相同的查询计划和IO。没有理由认为它们在性能上有所不同。检查您的时间统计并改善自己

–尼尔森
17-10-2在9:25

#2 楼

可接受的答案是短视的,问题有点松散:


1)都没有明确提及覆盖索引是否出现在
的左侧,右侧或两侧。

2)都没有考虑输入左侧集和
输入右侧集的大小。
(这个问题只提到总体上很大的结果集)。


我相信,当由于(1)和(2)导致成本存在显着差异时,优化器足够聪明,可以在“输入”与“存在”之间进行转换,否则可以只使用它作为提示(例如,存在鼓励使用右侧的可搜索索引的提示)。

两种形式都可以在内部转换为联接形式,颠倒联接顺序,并根据估计的行数(左右)和左边的索引存在情况以循环,哈希或合并方式运行,右侧或两侧。

评论


不知道为什么这个出色的答案没有得到更多关注。我同意理解双方的指数/结构可能会产生影响。说得好。

– SheldonH
2015年4月9日在20:57



优化器始终为IN和EXISTS提供相同的计划。尝试提出任何他们没有相同计划的情况(尽管这不适用于NOT IN和NOT EXISTS)

–马丁·史密斯
19年4月30日在12:17

@MartinSmith我假设您知道您在说什么,但是您有任何证据证明这些计划始终是相同的吗?如果是这样,它将消除长达十年之久的分歧。

– MarredCheese
19年6月6日在5:16

@MarredCheese-举一个例子来说明这一点的人有责任

–马丁·史密斯
19年6月6日在7:46

#3 楼

我已经在SQL Server 2005和2008上进行了一些测试,并且在EXISTS和IN上都返回了完全相同的实际执行计划,正如其他人所说的那样。优化器是最佳的。 :)

有一点要注意,如果您不正确地表达查询的话,EXISTS,IN和JOIN有时会返回不同的结果:http://weblogs.sqlteam.com/mladenp /archive/2007/05/18/60210.aspx

#4 楼

这里有许多误导性的答案,包括被高度评价的答案(尽管我不认为他们的意思有害)。简短的答案是:它们是相同的。

(T-)SQL语言中有很多关键字,但是最后,真正发生在硬件上的唯一事情就是所看到的操作在执行查询计划中。

调用[NOT] IN时执行的关系(数学理论)操作是半联接(使用[NOT] EXISTS时为反联接)。相应的sql-server操作具有相同的名称并非巧合。没有任何地方提到NOTIN的操作-仅(反)半联接。因此,在逻辑上等效的EXISTSIN选择不会影响性能,因为只有一种方法(反)半联接执行操作才能获得结果。

一个示例:

查询1(计划)

select * from dt where dt.customer in (select c.code from customer c where c.active=0)


查询2(计划)

select * from dt where exists (select 1 from customer c where c.code=dt.customer and c.active=0)


评论


你测试过了吗?如果是这样,您可以共享您的SQL和结果吗?

– UnhandledExcepSean
18/12/4在15:17

测试了多次。我可以创建另一个测试用例,但是可以,但是一个测试用例并不意味着优化器将对具有不同统计信息的表执行完全相同的计划。这可能会导致某人认为答案是部分的-但事实是多个半联接运算符不存在。也许我会在某个地方找到一个列表并将其链接。

–乔治·梅努蒂斯(George Menoutis)
18/12/4在15:20

#5 楼

我会通过IN使用EXISTS,请参见下面的链接:
SQL Server:JOIN vs IN vs EXISTS-逻辑差异

有一个普遍的误解,认为IN与EXISTS或JOIN的行为相同就返回结果而言。
IN:如果指定值与子查询或列表中的任何值匹配,则返回true。
存在:如果子查询包含任何行,则返回true。
联接:联接连接列上有2个结果集。

博客积分:https://stackoverflow.com/users/31345/mladen-prajdic

评论


哇,谢谢您的博客和解释。

–克里斯蒂安·穆勒(ChristianMüller)
7月15日7:38

#6 楼

在这些情况下,执行计划通常是相同的,但是直到您看到优化器如何将索引等所有其他方面都考虑在内时,您才真正不知道。

#7 楼

因此,IN与EXISTS不同,也不会产生相同的执行计划。

通常,在相关子查询中使用EXISTS,这意味着您将EXISTS内部查询与外部查询联接在一起。这将增加更多的步骤来产生结果,因为您需要解决外部查询联接和内部查询联接,然后匹配它们的where子句以将两者都联接。

通常使用IN而不将内部查询与外部查询,并且只能在一个步骤中解决(在最佳情况下)。

请考虑以下事项:


如果您使用IN和内部查询结果是数百万行不同的值,如果EXISTS查询是高性能的(具有与外部查询联接的正确索引),则它的执行速度可能会比EXISTS慢。
如果使用EXISTS并使用您的外部查询很复杂(需要花费更多的时间来执行,没有合适的索引),这会使查询速度因外部表中的行数而变慢,有时估计的完成时间可能以天为单位。如果行数对于给定的硬件是可接受的,或者数据的基数正确(例如,大数据集中的DISTINCT值较少),则IN的执行速度可能比EXISTS快。您在每个表上都有相当数量的行(公平地说,我的意思是某些内容超出了CPU处理和/或缓存的ram阈值)。

所以答案是DEPENDS。您可以在IN或EXISTS内编写一个复杂的查询,但是根据经验,当行数很多且具有许多不同的值时,应尝试使用有限的一组不同的值和EXISTS。 >
诀窍是限制要扫描的行数。

关于,

MarianoC

#8 楼

要优化EXISTS,请非常直白;只是需要一些东西,但实际上您不需要从相关子查询返回的任何数据。您只是在评估布尔条件。

所以:

WHERE EXISTS (SELECT TOP 1 1 FROM Base WHERE bx.BoxID = Base.BoxID AND [Rank] = 2)

因为相关子查询是RBAR,所以第一个结果命中条件为true,并且不会进一步处理。

评论


在使用LEFT JOIN + NULL编码时,我始终会非常谨慎,因为如果您对NULL的处理不十分小心,很容易错过或偏向结果。我很少遇到这样的情况,即EXISTS或CTE(用于查找重复项,或针对丢失的数据进行合成插入)不能同时满足相同的要求,并且性能不如LEFT JOIN + NULL

–乔什·刘易斯(Josh Lewis)
2014年4月5日在20:21

与EXISTS一起使用时,TOP 1应该完全无关紧要(或事件冗余)。找到所有匹配的行后,EXISTS总是返回。

–卡尔·基宁格(Karl Kieninger)
15年5月22日在16:22

到目前为止,我没有发现此方法对性能有任何好处。请显示执行计划的一些屏幕截图

– DaFi4
16年5月20日在8:55

#9 楼

不在我头上,并且不能保证是正确的:我相信在这种情况下第二个会更快。


在第一个示例中,相关的子查询很可能导致子查询针对每一行运行。
在第二个示例中,子查询应该仅运行一次,因为不相关。
在第二个示例中,IN一旦找到匹配项就会短路。