2009-02-06 73 views
14

好,所以我意識到這是一個非常模糊的問題,但忍受着我。爲什麼SQL連接選擇次優查詢計劃?

我在多次使用不同和不相關的查詢時遇到過這個問題。下面的查詢需要多少分鐘來執行:

SELECT <Fields> 
FROM <Multiple Tables Joined> 
    LEFT JOIN (SELECT <Fields> FROM <Multiple Tables Joined>) ON <Condition> 

然而,僅僅通過增加聯接提示其查詢的執行只需要幾秒鐘:

​​

奇怪的是在連接指定的類型提示並不是真的提高了性能。這似乎是因爲該提示會導致優化器孤立地執行子查詢,然後加入。如果爲子查詢創建表值函數(不​​是內聯函數),我會看到相同的性能改進。例如

SELECT <Fields> 
FROM <Multiple Tables Joined> 
    LEFT JOIN dbo.MySubQueryFunction() ON <Condition> 

有人有任何想法,爲什麼優化器在這種情況下是如此愚蠢?

+0

您使用的是哪個版本的SQL Server? – Austin 2009-02-06 22:05:44

+0

我在2005年和2008年都遇到過這個問題 – 2009-02-06 23:07:18

回答

13

如果這些表中的任何一個是表變量,優化器將使用0行的錯誤估計值,並且通常選擇嵌套循環作爲連接技術。

這是由於缺乏相關表格的統計數據。

+0

我沒有使用表變量,但在子查詢中經常出現視圖。儘管你的推理對我來說確實有意義。 – 2009-02-06 23:11:58

+1

當我刪除聯接提示時,查詢計劃發生了實質性變化,並引入了嵌套循環。我無法找到它在哪裏做出糟糕的行估計,但我不能再花更多時間尋找。 – 2009-02-07 01:27:17

7

優化器是一種算法。它不愚蠢或聰明,它按照它的編程方式工作。

Hash join意味着在較小的行源上構建一個散列表,這就是爲什麼必須首先執行內部查詢。

在第一種情況下,優化器可能選擇了nested loop。它將連接條件推入內部查詢,並在每次迭代時使用附加謂詞執行內部查詢。它可能找不到這個謂詞的適當索引,並且在每次迭代中確實發生了full table scan

很難說爲什麼會發生這種情況,除非您發佈精確查詢以及表中有多少行。

使用表函數不可能將連接條件推送到內部查詢中,這就是爲什麼它只能執行一次。

-4

SQL Server 2005內部:T-SQL查詢可以解答這些問題和其他許多問題。在我看過的T-SQL數據檢索和動詞處理的最好的外觀之一。 (不,我不是本書的作者,也不是本書的任何作者或作者,或微軟或微軟出版社的成員。這簡直是一項令人難以置信的工作,而且我已經轉向過去的各種DBA幾年後一致同意)。