2013-01-23 266 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查詢沒有這個問題。

我會猶豫不決地做出任何更好的表現,因爲這通常取決於發生什麼樣的優化。這就是爲什麼如果你關心性能,能夠找出執行計劃是很重要的。