联接顺序,是查询优化的最复杂问题之一,从七十年代以来,一直是广泛探索的主题。随着联接表的增加,搜索空间的扩大,必然导致计划数量的增大。
联接一次只能包括两个表,因此,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 AdventureWorksGOSELECT FirstName, LastNameFROM Person.Contact AS C JOIN Sales.Individual AS I ON C.ContactID = I.ContactID JOIN Sales.Customer AS Cu ON I.CustomerID = Cu.CustomerIDWHERE Cu.CustomerType = 'I'
从上面执行计划可以看到,表联接并没有按照T-SQL的输入顺序进行,而是,先CUSTOMER AND INDIVIUDAL,后再联接 CONTACT。
执行如下语句:
SELECT FirstName, LastNameFROM Person.Contact AS C JOIN Sales.Individual AS I ON C.ContactID = I.ContactID JOIN Sales.Customer AS Cu ON I.CustomerID = Cu.CustomerIDWHERE Cu.CustomerType = 'I'OPTION (FORCE ORDER)
这里,我们强制按照T-SQL联接,但是,开销增大了,第一个占总开销的38%,强制的是62%。
最后,应当知道,
1,如果是 左深联接,结果是 N!;
2,如果是 树丛联接,结果是 (2N-2)!/(N-1)!。