聯接順序,是查詢優化的最複雜問題之一,從七十年代以來,一直是廣泛探索的主題。隨着聯接表的增加,搜索空間的擴大,必然導致計劃數量的增大。
聯接一次只能包括兩個表,因此,N個表聯接有 N-1次聯接。當然,下一個聯接不需要等到上一個聯接完成。
兩個屬性:
1,交換
A JOIN B = B JOIN A
它確定那個表作爲第一個表,例如,在 NESTED LOOP JOIN 中,第一個表是作爲外部表,第二個是內部表;在 HASH JOIN 中,第一個表作爲 BUILD,第二個是 PROBE。
2,相關
(A JOIN B) JOIN C = A JOIN (B JOIN C)
它確定表聯接的順序,例如,等號左邊,首先 A JOIN B,然後中間結果再聯接 C,而右邊是,先 B JOIN C,後結果再聯接A。
毫無疑問,聯接的交換和相關屬性,產生了表聯接的不同排列,而每個排列的開銷是不同的,當然,最終的決定在於查詢優化器。
好吧,看個例子:
USE AdventureWorks
GO
SELECT FirstName, LastName
FROM Person.Contact AS C
JOIN Sales.Individual AS I ON C.ContactID = I.ContactID
JOIN Sales.Customer AS Cu ON I.CustomerID = Cu.CustomerID
WHERE Cu.CustomerType = 'I'
從上面執行計劃可以看到,表聯接並沒有按照T-SQL的輸入順序進行,而是,先CUSTOMER AND INDIVIUDAL,後再聯接 CONTACT。
執行如下語句:
SELECT FirstName, LastName
FROM Person.Contact AS C
JOIN Sales.Individual AS I ON C.ContactID = I.ContactID
JOIN Sales.Customer AS Cu ON I.CustomerID = Cu.CustomerID
WHERE Cu.CustomerType = 'I'
OPTION (FORCE ORDER)
這裏,我們強制按照T-SQL聯接,但是,開銷增大了,第一個佔總開銷的38%,強制的是62%。
最後,應當知道,
1,如果是 左深聯接,結果是 N!;
2,如果是 樹叢聯接,結果是 (2N-2)!/(N-1)!。