接下來的文章是記錄自己曾經的盲點,同時也透漏了自己的發展歷程(可能發展也算不上,只能說是瞎混)。當然,一些盲點也在工作和探究過程中慢慢有些眉目,現在也願意發揚博客園的奉獻精神,拿出來和大家分享一下。
開門見山,直接入題
在進行Join的時候,數據庫優化器是怎么進行聯接呢?下面我們也詳細的講述。
在SQL Server中,有3中Join的策略——哈希匹配(Hash)、合並(Merge)、嵌套循環(Nested Loop).
在理解者三種聯接策略之前,我們先來簡單了解下哈希匹配聯接、合並聯接、嵌套循環聯接,
哈希匹配聯接:這種聯接有兩種輸入,即建立輸入和探測輸入。首先SQL Server會根據統計信息從兩張表中篩選出較小的表作為建立輸入,並且讀入所有行,然后在內存中根據關聯條件建立一個哈希表。在整個建立階段完成之后就進入探測階段。以后一行一行的對探測輸入進行掃描和計算,並為每個探測行計算哈希值,然后進行匹配(當然這里也分多種情況,建立輸入大於可用內存時等其他情況)。
合並聯接:合並連接要求兩個輸入都要在合並列上排序。由於每個輸入都已排序,因此Merge Join運算符將從每個輸入中獲取一行進行比較,如果行相等則進行返回,不等則舍棄。當數據量不大的時候,這種聯接方式比哈希匹配更加有效。
嵌套循環聯接:嵌套循環也稱“嵌套迭代”,他將一個聯接輸入用作外部輸入表,將另一個聯接輸入用作內部輸入表。外部循環逐行處理外部輸入表。內部循環逐行處理外部輸入表,內部循環會針對每個外部行執行,在內部輸入表中搜索匹配的行。
通過上面的介紹,我們也能分析出來(可以根據時間復雜度,和空間復雜度),以上三種聯接並沒有絕對的優劣。
大致可以分一下幾種情況:
(1)當數據量容量很大,且未排序的情況下,哈希匹配要優於其他兩種。
(2)當屬數據已經排序,且數據量不大的之后,合並連接更加有效。
(3)當結果集比較小,且數據容量不大的時候嵌套循環比較合適。
下面我們可以通過測試來查看SQL Server優化器的選擇。
我們先創建兩張表(Headers和Details):
1.執行下面查詢,查看執行計划:
select *
from Headers
inner join Details on Headers.ID=Details.HeaderID
go
2.查看執行計划,可以看出查詢優化器使用了哈希匹配:

3.在兩表中創建聚集索引
create nonclustered index index_details_headerID on details(headerID)
create unique clustered index index_details_ID_headerID on details(headerID,ID)
4、執行上面查詢,開啟執行計划,可以看出此時優化器使用了合並聯接

5.現在執行下面查詢語句(帶where 過濾):
select *from Headers inner join Details on Headers.ID=Details.HeaderID where Details.ID=500
6.通過查看執行計划得出,當結果集比較小的時候優化器選擇了嵌套循環:

總結
通過上面的我們可以得出,三種聯接各有優略,視乎情況而定。但是如果可以的話,應該在關聯列上建立索引。
