2011-03-25 49 views
2

例如,假設你有一個這樣的查詢:什麼時候有利於約束SQL Server 2005中的連接?

SELECT * 
FROM table1 t1 
JOIN table2 t2 ON t1.field1 = t2.field1 AND t1.year = t2.year 
JOIN table3 t3 ON t1.field1 = t3.field1 AND t1.year = t3.year 
JOIN table4 t4 ON t3.field2 = t4.field2 AND t3.year = t4.year 
WHERE t1.year = '2010' 

它更快做到這一點:

SELECT * 
FROM table1 t1 
JOIN table2 t2 ON t1.field1 = t2.field1 AND t1.year = t2.year AND t2.year = '2010' 
JOIN table3 t3 ON t1.field1 = t3.field1 AND t1.year = t3.year AND t3.year = '2010' 
JOIN table4 t4 ON t3.field2 = t4.field2 AND t3.year = t4.year AND t4.year = '2010' 
WHERE t1.year = '2010' 

它並不總是顯而易見的,這將是「快」。有時候,SQL Server 2005中的執行計劃說一個比另一個快,這取決於索引。有時它會執行所有散列匹配,這看起來是CPU密集型的,而排序然後是合併連接似乎更加IO密集。考慮到執行計劃的結果,真實世界的結果並不總是反映人們的期望。


有人能爲我澄清一個比另一個更好的簡單場景嗎?或者至少驗證我的理解是否正確?在我看來,如果你加入索引良好的列,那麼不用限制一年或某些其他數據的連接會更有效,因爲它可以使用基於索引的哈希匹配,並且不需要排序並使用臨時表。但是,如果您在兩個查詢中選擇並參與非索引列,那麼添加時間約束會導致更少的行被處理,並導致更快的排序和合並連接,即使它引發了一些(更多? )IO成本。


而且,它困擾着我,從表2不考慮價值的有限的子集,從上表1 where子句中產生的預連接選擇,它似乎從表2選擇所有的行不使用時對連接的限制。由於table1中的行將會受到限制b WHERE t1.year ='2010'且連接受t1.year = t2.year限制,因此不應該認爲連接只需要查看table2,其中year =' 2010' ?

我想知道爲什麼它沒有先查看where子句,並且在連接之前只選擇匹配的行,我相信這背後有一些很好的推理,但它逃脫了我,根據執行計劃中,在這種情況下,從table2查看的行數會發生變化,具體取決於是否將t2.year ='2010'添加到連接中。

預先感謝您,對於長期的問題感到抱歉。我想盡可能清楚。請原諒我的缺乏經驗。

+1

既然你問:「我不知道爲什麼它不看where子句第一「,我想我會告訴你邏輯查詢處理順序如下所示的信息:FROM(此步驟的一個子集創建基於連接和它們的ON篩選等的虛擬表),WHERE,GROUP BY ,HAVING,SELECT(這裏的一部分步驟處理SELECT列表中的元素),然後ORDER BY被最後處理。 (還有幾個子步驟我沒有包括在內。) – 2011-03-28 13:23:50

回答

5

「它快嗎?」編號

查詢優化器將決定哪個是最嚴格的結果集篩選器(如果您的統計信息是最新的,通常會做得很好)。

+0

+1雖然它取決於確切的查詢。即使在這種簡單的情況下,也可以「欺騙」SQL Server(甚至是2008),甚至可以選擇一些不好的計劃......但是,大部分......是的。 – 2011-03-25 05:50:33

+0

我有一個查詢,類似於上面,需要:50沒有時間限制和:20與它一致。根據exec計劃,差異似乎是一系列RID查找。任何有關這種情況的見解? (我知道這不是很好,因爲我沒有給你一個確切的例子,只是對可能性感到好奇。) – John 2011-03-25 10:11:21

+0

@John:我會發布執行計劃 – 2011-03-25 11:03:24

1

有一個額外的過濾器不會增加任何值:優化器已經解決了。儘管如此,它使代碼難以維護。

您可以OUTER做它加入,因爲你不能在外部表的WHERE過濾器(更改的INNER JOIN):

SELECT * 
FROM table1 t1 
LEFT JOIN 
table2 t2 ON t1.field1 = t2.field1 AND t1.year = t2.year and t2.x = 1 
JOIN 
table3 t3 on t1.field1 = t3.field1 AND t1.year = t3.year 
... 
WHERE 
t1.year = '2010' 
+0

感謝它在外連接上有意義。 – John 2011-03-25 10:08:36