2013-01-23 268 views
2

我一些优化SQL查询(这可以被认为是一个问题,我最近公布的第2部分),并更换一些不符合NOT EXISTS谓词NOT EXISTS VS NOT IN

我是正确的思维,主受益于这样做是与NOT EXISTS你得到的好处是,当一个找到匹配的声明会终止,但不与计数子查询将不得不做全表扫描?

它似乎也不需要额外的工作,如果选择的数据包含NULL,这是正确的吗?

我需要确保的是,第二条语句比这两种情况下,第一(和功能上等同)更好的之前,我实现它们在proc:

案例1:

 --exclude sessions that were tracked as part of a conversion during the last response_time minutes 
     -- AND session_id NOT IN (SELECT DISTINCT tracked_session_id  
     --        FROM data.conversions WITH (NOLOCK) 
     --        WHERE client_id = @client_id 
     --        AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date) 
     --        AND utc_date_completed <= @date  
     --        AND utc_date_clicked <= @date) 

     AND NOT EXISTS (SELECT 1 
          FROM data.conversions WITH (NOLOCK) 
          WHERE client_id = @client_id 
          AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date) 
          AND utc_date_completed <= @date 
          AND utc_date_clicked <= @date 
          AND data.conversions.tracked_session_id = d.session_id 
     ) 

案例2 :

 -- NOT EXISTS vs full table scan with COUNT(dashboard_id)         
     -- AND (SELECT COUNT(dashboard_id) 
     --   FROM data.dashboard_responses WITH(NOLOCK) 
     --   WHERE session_id = d.session_id 
     --   AND cycle_id = cy.id 
     --   AND client_id = @client_id) = 0 

     AND NOT EXISTS(SELECT 1 
          FROM data.dashboard_responses 
          WHERE session_id = d.session_id 
          AND cycle_id = cy.id 
          AND client_id = @client_id) 

干杯

+4

是否执行计划不会告诉你如果不只会产生一个不同的计划,更聪明执行表扫描?我会亲自看看计划中有关性能/ IO统计数据的内容。 –

+1

可能的重复[有什么区别不存在与不存在与左连接是NULL?](http://stackoverflow.com/questions/2246772/whats-the-difference-between-not-exists-vs – GarethD

+0

不幸的是,我不能(轻松地)针对数据源运行这些存储过程以获得查询计划 – managedheap84

回答

5

正如你所说的那样这两个是不同的东西。如果项目的子查询中不包含IN因为没有等于NULLNULL没有结果将被退回并没有什么不等于NULL(甚至NULL)。

假设您使用两者来实现相同的结果,只要您在IN语句中处理NULL值,两者之间就没有区别。优化器足够聪明,知道用NULL值消除了,或者与不可空列相同,所以使用相同的ANTI SEMI JOIN

考虑这两个表:

CREATE TABLE T (ID INT NOT NULL PRIMARY KEY); 
CREATE TABLE T2 (ID INT NOT NULL PRIMARY KEY); 

这两个查询得到完全相同的执行计划:

SELECT * 
FROM T 
WHERE ID NOT IN (SELECT ID FROM T2); 

SELECT * 
FROM T 
WHERE NOT EXISTS (SELECT ID FROM T2 WHERE T.ID = T2.ID); 

因为优化器知道T2.ID是一个非空列。随着第三个表:

CREATE TABLE T3 (ID INT); 

其中ID列既不是索引或为空的这两个查询呈现非常不同的执行计划:

SELECT * 
FROM T 
WHERE ID NOT IN (SELECT ID FROM T3); 

SELECT * 
FROM T 
WHERE NOT EXISTS (SELECT ID FROM T3 WHERE T.ID = T3.ID); 

和NOT EXISTS将更加高效。然而这两个再次产生(基本上)相同的执行计划:

SELECT * 
FROM T 
WHERE ID NOT IN (SELECT ID FROM T3 WHERE T3.ID IS NOT NULL); 

SELECT * 
FROM T 
WHERE NOT EXISTS (SELECT ID FROM T3 WHERE T.ID = T3.ID); 

所有这些查询和样本数据都在SQL Fiddle

编辑

要真正回答你的问题:

案例1将与NOT INNOT EXISTS相同,如果tracked_session_iddata.conversions中的一个不可空列,或者您在In语句中添加WHERE tracked_Session_id IS NOT NULL。如果该列不是空值,并且不排除空值,则性能不会相同,并且假设没有空值将会表现更好,如果没有空值,结果将不会相同,因此性能没有可比性。

案例2居然让我惊讶的样本数据,我曾以为这不会被优化为ANTI SEMI JOIN,并已书面答复说为多,但只是在保存编辑之前,我想我最好检查,并惊讶地看到这个:

SELECT * 
FROM T 
WHERE ( SELECT COUNT(*) 
      FROM T3 
      WHERE T.ID = T3.ID 
     ) = 0; 

优化完全一样NOT EXISTS。因此,它的出现是优化器甚至比我想象的,如果你想计数是其他东西比0

SQL Fiddle for Case 2

+0

在mssql 2005中,由于许多人使用IF语句的语法,他们添加了对count(*)= 0和count(*)> 0的优化。虽然存在是更好的选择,因为技术上是正确的。 http://blogs.technet.com/b/wardpond/archive/2007/08/27/if-exists-select-vs-if-select-count-1-0.aspx –

-2

NOT EXISTS运行曲ery,对行进行计数,如果count == 0,则返回true

NOT IN运行查询,对结果进行迭代,给定的值进行比较的结果,如果没有匹配,则返回true

通常情况下,第一种方法是要快得多。

当然,您必须小心,从周围的查询中包含到子查询中的列/值是什么,因为这可能导致子查询运行N次(每次在外部结果集中运行一次)。

还有另一种方法:将表A连接到表B的OUTER JOIN,并检查表B中的列是否为NULL。这会只运行一次子查询。它只适用于更简单的情况(不适用于多表连接链)。

+5

不是很明显,因为“NOT EXISTS”可以尽快终止发现一个匹配,同样,'NOT IN'可以被优化以执行'LEFT ANTI SEMI JOIN',当它找到它的第一个匹配时它也会终止,并且可以使用索引。 “NOT EXISTS”和“NOT IN”都优化为使用“LEFT ANTI SEMI JOIN”。 –

+1

这是非常错误的。正如@ChrisChilvers所说的那样,他们都以LEFT ANTI SEMI JOIN的形式运行。区别在于NULL是如何处理的 – gbn

+0

@ChrisChilvers有趣的知道。你能提供一些参考吗? – gaborsch

2

你是正确的,有与空值有很大的区别。 A NOT IN查询检查每个元素明确不匹配。与null比较不会产生明确的结果。因此如果你的子查询中包含一个空值,没有什么会被认为是“NOT IN”它。

See this SQL Fiddle example.

此行为的不直观副作用是NOT IN实际上不是的IN相反。

A NOT EXISTS查询没有这个问题。

我会犹豫不决地做出任何更好的表现,因为这通常取决于发生什么样的优化。这就是为什么如果你关心性能,能够找出执行计划是很重要的。