具有多個連接的 SQL 查詢的執行計劃的邏輯順序
我知道 SQL 查詢的執行邏輯順序是:
FROM ON JOIN WHERE GROUP BY WITH CUBE or WITH ROLLUP HAVING SELECT DISTINCT ORDER BY TOP
如果查詢中有多個連接會發生什麼,例如,如果我們有這樣的查詢:
SELECT * FROM user_branch T1 INNER JOIN dimcustomer2 T2 ON T1.BRANCH_CODE = T2.BRANCH_CODE INNER JOIN customer_guarantee T3 ON T3.CUSTOMER_NUM = T2.CUSTOMER_NUM
一些範例數據:
customer_guarantee: CUSTOMER_NUM BRANCH_CODE ------------------------------- A X B X C Y D Z user_branch: USER_ID BRANCH_CODE -------------------------------- U1 Y dimcustomer2: CUSTOMER_NUM BRANCH_CODE -------------------------------- A Y B Y C Y D Z
這將如何執行?哪個聯接將首先執行?如果查詢中有不同類型的連接怎麼辦?在這種情況下執行連接的順序是什麼?提前致謝。
確定連接邏輯順序的一種方法是將範例中的第一個內連接替換為左外連接:
SELECT * FROM user_branch T1 **LEFT** JOIN dimcustomer2 T2 ON T1.BRANCH_CODE = T2.BRANCH_CODE INNER JOIN customer_guarantee T3 ON T3.CUSTOMER_NUM = T2.CUSTOMER_NUM
讓我們假設 中的某些行在 中
T1
沒有匹配項T2
。更具體地說,讓我們假設這些是三個表:T1 T2 T3 BRANCH_CODE BRANCH_CODE CUSTOMER_NUM CUSTOMER_NUM ----------- ----------- ------------ ------------ 11 11 230 120 12 12 235 170 13 15 260 230 14 235 15 245 250 260 270
這裡有兩個連接以及它們執行順序的兩種可能性。
1. 左連接,然後內連接
如果左連接首先計算,那麼它的結果將在行不匹配的
T2
列中包含空值:T1
T1.BRANCH_CODE T2.BARNCH_CODE T2.CUSTOMER_NUM -------------- -------------- --------------- 11 11 230 12 12 235 13 *(空)* *(空)* 14 *(空)* *(空)* 15 15 260
T3
通過在使用列的條件上使用內部連接進一步連接該結果T2
將消除不匹配 - 因此,相應T1
的行 - 因為 null 不能滿足連接的等於條件:T1.BRANCH_CODE T2.BARNCH_CODE T2.CUSTOMER_NUM T3.CUSTOMER_NUM -------------- -------------- --------------- --------------- 11 11 230 230 12 12 235 235 15 15 260 260
這樣,一些
T1
行將從最終結果集中排除。2. 內連接,然後左連接
現在,如果首先執行內部連接,那麼它將生成一個包含來自
T2
且T3
匹配內部連接條件的行的結果集:T2.BARNCH_CODE T2.CUSTOMER_NUM T3.CUSTOMER_NUM -------------- --------------- --------------- 11 230 230 12 235 235 15 260 260
當此結果集外連接到
T1
時,T1
在外側,您將獲得一個最終結果,其中包含與外連接條件匹配的 - 內連接中T1
的T2
所有行:T3
T1.BRANCH_CODE T2.BARNCH_CODE T2.CUSTOMER_NUM T3.CUSTOMER_NUM -------------- -------------- --------------- --------------- 11 11 230 230 12 12 235 235 13 *(空)* *(空)* *(空)* 14 *(空)* *(空)* *(空)* 15 15 260 260
因此,第二種解釋意味著所有
T1
行都應該出現在結果中。由於這兩種解釋給出瞭如此不同的結果,很明顯只有一種是正確的。執行查詢,您會看到它實際上是第一個。這意味著從邏輯上講,連接按照它們在子句****中指定的順序執行
FROM
。語法變化
請注意,上面的結論適用於最傳統的連接語法,即:
FROM T1 ... JOIN T2 ON ... ... JOIN T3 ON ... ...
您的範例與該模式匹配,因此結論也適用於它。然而,有一些變化值得一提,我們的結論不適用,或者至少不那麼直截了當。
1.嵌套JOIN語法
從語法上講,可以在另一個連接中指定連接,如下所示:
FROM T1 JOIN T2 JOIN T3 ON .. ON ...
在上述情況下,
JOIN T2
是之前遇到的JOIN T3
。然而,前一個連接的聲明在這一點上並不完整:它的ON
子句是末尾的那個,並且僅在該JOIN T3 ON ...
部分之後進行邏輯評估。所以在這種情況下,T2
首先連接到T3
,然後連接的結果連接到T1
。您仍然可以爭辯說我們的結論站在這裡,儘管在這種情況下它並不那麼明確。我們得出結論,連接是按照它們在子句中指定的順序進行評估的。
FROM
在這個例子中,我們在解析FROM
子句時遇到的第一個連接,到第二個連接的時候還沒有完全指定。2.混合逗號連接和正常連接
在引入顯式
JOIN
語法之前,連接是這樣指定的:FROM T1, T2, T3 WHERE <joining conditions, filter conditions>
大多數(如果不是全部)平台(包括 SQL Server)仍然支持這種類型的連接,有時稱為逗號連接。
如果沒有連接條件,逗號連接本質上是交叉連接。連接條件使其成為內部連接。但是,您可以看到,在這種情況下,連接條件出現在一個完全不同的子句中,即
WHERE
子句。現在,SQL Server 允許您在同一
FROM
個子句中混合使用逗號連接和正常連接。當您混合使用這樣的連接時:FROM T1, T2 JOIN T3 ON ... , T4 ...
SQL Server 將在將它們全部交叉連接在一起之前獨立評估每個單獨的逗號分隔項。因此,在上述情況下,
T2 JOIN T3 ON ...
連接將在其結果被交叉連接之前進行評估T1
(通過可能在WHERE
子句中找到的任何連接條件進一步過濾)。我們的結論在這裡根本不適用。但是,您可以看到在這種情況下使用了非常不同的語法。我在 Stack Overflow: The multi-part identifier could not be bound 的回答中更詳細地討論了混合語法。