SQL Server IN与EXISTS性能

时间:2010-01-14 15:43:41

标签: sql-server sql-server-2005 exists query-performance sql-in

我很好奇以下哪一项会更有效率?
我一直对使用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])

9 个答案:

答案 0 :(得分:130)

EXISTS会更快,因为一旦发动机发现了撞击,它就会退出,因为条件证明是正确的。
使用IN,它将在进一步处理之前从子查询中收集所有结果。

答案 1 :(得分:35)

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

要注意的是,如果你没有恰当地表达你的查询,EXISTS,IN和JOIN有时会返回不同的结果:http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx

答案 2 :(得分:35)

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

  

1)两者都没有明确提及是否存在覆盖指数   左,右或两侧。

     

2)既没有考虑输入左侧设置的大小和   输入右侧设置。
        (问题只是提到了一个整体的大型结果集)。

我相信优化器足够聪明,当由于(1)和(2)导致显着的成本差异时,在“in”和“exists”之间进行转换,否则它可能仅用作提示(例如,存在于鼓励在右侧使用可寻找的指数)。

两个表单都可以在内部转换为连接表单,反转连接顺序,并根据估计的行数(左和右)和左,右或两者的索引存在运行循环,散列或合并侧上。

答案 3 :(得分:3)

我会在IN上使用EXISTS,请参阅以下链接:

SQL Server: JOIN vs IN vs EXISTS - the logical difference

答案 4 :(得分:3)

在这些情况下,执行计划通常是相同的,但在你看到优化器如何影响索引的所有其他方面等之前,你真的永远不会知道。

答案 5 :(得分:2)

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

通常在相关子查询中使用EXISTS,这意味着您将使用外部查询加入EXISTS内部查询。这将添加更多步骤来生成结果,因为您需要解决外部查询连接,然后内部查询连接匹配其where子句以加入两者。

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

考虑一下:

  1. 如果使用IN并且内部查询结果是数百万行不同的值,则鉴于EXISTS查询是高性能的(具有与外部查询连接的正确索引),它可能会执行SLOWER而不是EXISTS。

  2. 如果使用EXISTS并且外部查询的连接很复杂(需要更多时间来执行,没有合适的索引),它将使查询减慢外表中的行数,有时估计时间为完成可以在几天内完成。如果给定硬件的行数是可接受的,或者数据的基数是正确的(例如,大数据集中的DISTINCT值较少)IN的执行速度可能比EXISTS快。

  3. 当每个表上有相当数量的行时,会注意到以上所有内容(通过公平,我的意思是超出CPU处理和/或缓存的ram阈值)。

  4. 所以答案是ANSWER。您可以在IN或EXISTS中编写复杂查询,但根据经验,当您有许多具有大量不同值的行时,您应该尝试使用IN和一组有限的不同值和EXISTS。

    诀窍是限制要扫描的行数。

    此致

    MarianoC

答案 6 :(得分:1)

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

所以:

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

因为相关的子查询是RBAR,所以第一个结果命中使条件为真,并且不再进行处理。

答案 7 :(得分:1)

这里有许多误导性的答案,包括被高度评价的答案(尽管我不认为他们的操作会带来伤害)。 简短的答案是:这些都是相同的。

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

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

一个例子:

查询1(plan

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

查询2(plan

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

答案 8 :(得分:-1)

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

  1. 在第一个中,相关子查询可能会导致每行运行子查询。
  2. 在第二个示例中,子查询应该只运行一次,因为不相关。
  3. 在第二个示例中,IN会在找到匹配后立即短路。