2011-10-12 130 views
3

考慮:SQL查詢優化JOIN

數據表Y

  • id int clustered index
  • name nvarchar(25)

表anothertable

  • id int clustered Index
  • name nvarchar(25)

表someFunction

  • 然後做一些數學返回一個有效的ID

比較:

SELECT y.name 
    FROM y 
WHERE dbo.SomeFunction(y.id) IN (SELECT anotherTable.id 
            FROM AnotherTable) 

VS:

SELECT y.name 
    FROM y 
    JOIN AnotherTable ON dbo.SomeFunction(y.id) ON anotherTable.id 

問題:

雖然定時這兩個查詢出我發現,在大的數據集使用IN所述第一查詢的速度要快得多然後使用INNER JOIN所述第二查詢。我不明白爲什麼有人可以幫忙解釋一下。

Execution Plan

+1

請參閱優化器/解釋計劃 - 我們無法告訴您數據發生了什麼。 –

+0

我不知道,但我猜想這是因爲在IN情況下它從另一個表獲得id的列表一次,而在INNER連接中,它有效地準備記錄的全部外部產品並檢查每一個。您的函數調用阻止它對其自身進行任何優化。 –

+0

@OMG小馬 - 我注意到這個使用多個不同的數據集。這是我覺得數據不可知的行爲。 – gh9

回答

5

一般來說INJOIN其中一個JOIN可以返回其他行,其中一行在JOIN -ed表中具有多個匹配項。

從你的估計執行計劃,雖然可以看出,在這種情況下,2個查詢在語義上是相同的

SELECT 
     A.Col1 
     ,dbo.Foo(A.Col1) 
     ,MAX(A.Col2) 
     FROM A 
     WHERE dbo.Foo(A.Col1) IN (SELECT Col1 FROM B) 
    GROUP BY 
     A.Col1, 
     dbo.Foo(A.Col1) 

SELECT 
     A.Col1 
     ,dbo.Foo(A.Col1) 
     ,MAX(A.Col2) 
     FROM A 
     JOIN B ON dbo.Foo(A.Col1) = B.Col1 
    GROUP BY 
     A.Col1, 
     dbo.Foo(A.Col1)  

即使重複由JOIN隨後介紹了他們將被GROUP BY刪除,因爲它只引用左手錶中的列。此外,這些重複行不會改變結果,因爲MAX(A.Col2)不會更改。然而,對於所有總量來說,情況並非如此。如果您要使用SUM(A.Col2)(或AVGCOUNT),則重複項的存在會改變結果。

似乎SQL Server沒有任何邏輯來區分諸如MAXSUM之類的聚合,因此很可能它將所有重複項擴展出來,然後再聚合它們,並且只是做了很多工作。

被聚合行的估計人數是2893.54IN VS 28271800JOIN但這些估計不一定是非常可靠的連接謂詞是unsargable。

+0

我很欣賞您在上傳信息時花時間解釋和承擔的時間。非常感謝你!! – gh9

2

你的第二個查詢是有點好笑 - 你可以試試這個代替?

SELECT y.name 
FROM dbo.y 
INNER JOIN dbo.AnotherTable a ON a.id = dbo.SomeFunction(y.id) 

這有什麼區別嗎?

否則:看執行計劃!並可能在這裏發佈。在不知道更多關於你的表格(數據量和數據分佈等)和你的系統(RAM,磁盤等)的情況下,真的很難給出「全局」有效的語句

2

好吧,首先,擺脫由dbo.SomeFunction(y.id)暗示的標量UDF。 That will kill your performance real good。即使你用一行內聯表值函數替換它,它也會更好。

至於你的實際問題,我發現在其他情況下也有類似的結果,並且同樣困惑。優化器只是以不同的方式對待它們;我會很高興看到別人提供的答案。

+0

+1好建議:「暗含的標量UDF」 - 我沒有立即發現的東西;) – onedaywhen