在查看sql執行計劃時,我們會發現表的連接方式有多種,本文對錶的連接方式進行介紹以便更好看懂執行計劃和理解sql執行原理。
一、連接方式:
嵌套循環(Nested Loops (NL))
(散列)哈希連接(Hash Join (HJ))
(歸併)排序合併連接(Sort Merge Join (SMJ) )
二、連接說明:
1.Oracle一次只能連接兩個表。不管查詢中有多少個表,Oracle 在連接中一次僅能操作兩張表。
2.當執行多個表的連接時,優化器從一個表開始,將它與另一個表連接;然後將中間結果與下一個表連接,以此類推,直到處理完所有表爲止。
三、表連接詳解:
1.嵌套循環(Nested Loops (NL)):
嵌套循環實現機制(僞代碼):
For r1 in (select rows from table_1 where colx={value})
loop
for r2 in (select rows from table_2 that match current row from table_1)
loop
output values from current row of table_1 and current row of table_2;
end loop;
End loop;
這段代碼由兩個循環構成。
嵌套循環中的這兩個表通常稱爲外部表(outer table)和內部表(inner table)。
在嵌套循環連接中,外部表又稱爲驅動表(driver table)
僞代碼中:table_1爲驅動表,table_2爲內表
從僞代碼中可以看出該連接過程就是一個2層嵌套循環,所以外層循環的次數越少越好,這也就是我們爲什麼將小表或返回較小結果集的表作爲驅動表的原因。
2.(散列)哈希連接(Hash Join (HJ)):
Hash join一般用於一張小表和一張大表進行join時。在絕大多數情況下,hash join效率比其他join方式效率更高。
對於hash join的詳細理解,可參看網上一篇文章寫的比較透徹:http://www.hellodba.com/reader.php?ID=144&lang=cn
3.排序合併連接(Sort Merge Join (SMJ) ):
通常情況下散列連接的效果都比排序合併連接要好,然而如果行源已經被排過序,在執行排序合併連接時不需要再排序了,這時排序合併連接的性能會優於散列連接。可以使用USE_MERGE(table_1 table_2)來強制使用排序合併連接。
過程:將兩個表排序,然後將排序後兩個表合併。
四、連接方式總結:
1))嵌套循環(nest loop):
對於被連接的數據子集較小的情況,嵌套循環連接是較好的選擇。在嵌套循環中,外表驅動內表,外表返回的每一行都要在內表中檢索找到它匹配的行,因此整個查詢返回的結果集不能太大(大於10000不合適),要把返回子集較小的表作爲外表(驅動表),而且在內表的連接字段上一定要有索引。
2)哈希連接(hash join):
哈希連接是大數據集連接時常用的方式,優化器使用兩個表中較小的表,利用連接鍵在內存中建立散列表,然後掃描較大的表並探測散列表,找出與散列表匹配的行。
這種方式適用於較小的表完全可以放入內存的情況,這樣成本就是訪問兩個表的成本之和。但是在表很大的情況下並不能完全放入內存,這時優化器將它分割成若干不同的分區,不能放入內存的部分就把該分區寫入磁盤的臨時段。
哈希連接只能應用於等值連接(如WHERE A.COL3 = B.COL4)、非等值連接(WHERE A.COL3 > B.COL4)、外連接(WHERE A.COL3 = B.COL4(+))。
3)排序合併連接(Sort Merge Join )
通常情況下哈希連接的效果都比排序合併連接要好。然而如果行源已經被排過序,在執行排序合併連接時不需要再排序了,這時排序歸併連接的性能會憂於哈希連接。
五、連接方式應用場景:
1. 哈希連接只適用於等值連接。
2. 嵌套循環是行源連接方式,只適合小量數據連接。
哈希連接和排序合併連接是集合連接方式,適合大量數據連接。
3. 在等值連接方式下,返回少量記錄(<10000)且內部表在連接列上存在索引,適合嵌套循環連接。若返回大量記錄則適合哈希連接。
4. 在等值連接方式下,兩個行源集合都很大,若連接列是高基數列,則適合哈希連接,否則適合排序合併連接。
5. 嵌套循環連接可以先返回已經連接的行,而不必等待所有的連接操作處理完才返回數據。而其它兩種連接方式則不行。
6. 排序合併連接的兩個數據集可以並行處理,而嵌套循環和哈希連接不能.