nested loop
對於被連線的資料子集較小的情況,nested loop連線是個較好的選擇。nested loop就是掃瞄乙個表,每讀到一條記錄,就根據索引去另乙個表裡面查詢,沒有索引一般就不會是 nested loops。
一般在nested loop中, 驅動表滿足條件結果集不大,被驅動表的連線欄位要有索引,這樣就走nstedloop。如果驅動表返回記錄太多,就不適合nested loops了。如果連線字段沒有索引,則適合走hash join,因為不需要索引。
可用ordered提示來改變cbo預設的驅動表,可用use_nl(table_name1 table_name2)提示來強制使用nested loop。
hash join
hash join是cbo 做大資料集連線時的常用方式。優化器掃瞄小表(或資料來源),利用連線鍵(也就是根據連線字段計算hash 值)在記憶體中建立hash表,然後掃瞄大表,每讀到一條記錄就來探測hash表一次,找出與hash表匹配的行。
當小表可以全部放入記憶體中,其成本接近全表掃瞄兩個表的成本之和。如果表很大不能完全放入記憶體,這時優化器會將它分割成若干不同的分割槽,不能放入記憶體的部分就把該分割槽寫入磁碟的臨時段,此時要有較大的臨時段從而盡量提高i/o 的效能。臨時段中的分割槽都需要換進記憶體做hash join。這時候成本接近於全表掃瞄小表+分割槽數*全表掃瞄大表的代價和。
至於兩個表都進行分割槽,其好處是可以使用parallel query,就是多個程序同時對不同的分割槽進行join,然後再合併。但是複雜。
使用hash join時,hash_area_size初始化引數必須足夠的大,如果是9i,oracle建議使用sql工作區自動管理,設定workarea_size_policy 為auto,然後調整pga_aggregate_target即可。
以下條件下hash join可能有優勢:
兩個巨大的表之間的連線。
在乙個巨大的表和乙個小表之間的連線。
可用ordered提示來改變cbo預設的驅動表,可用use_hash(table_name1 table_name2)提示來強制使用hash join。
sort merge join
sort merge join的操作通常分三步:對連線的每個表做table access full;對table access full的結果進行排序;進行merge join對排序結果進行合併。sort merge join效能開銷幾乎都在前兩步。一般是在沒有索引的情況下,9i開始已經很少出現了,因為其排序成本高,大多為hash join替代了。
通常情況下hash join的效果都比sort merge join要好,然而如果行源已經被排過序,在執行sort merge join時不需要再排序了,這時sort merge join的效能會優於hash join。
在全表掃瞄比索引範圍掃瞄再通過rowid進行表訪問更可取的情況下,sort merge join會比nested loops效能更佳。
可用use_merge(table_name1 table_name2)提示強制使用sort merge join。
為何nested loop要求小表驅動,hash join又為何要求小表hashed**)
nested loop的過程:選擇row resource 最小的那個表作為驅動表(外部表),內部表要求有選擇性高的index。 從外部表(驅動表)裡一次取一行對內部表的每行進行比較,即外部表有幾個distinct行,就有幾次nested loop。
所以nested loop的代價是:
cost = outer access cost + (inner access cost * outer cardinality)
outer access cost應該是讀取驅動表到記憶體,而內部表要求有有效的index也是為了降低inner access cost,而驅動表要求小,也就很好理解了。
hash join 在缺少index的情況下比nested loop更有效,一般情況下比nested loop更快,因為處理記憶體中的hash錶比b-tree index更迅速。有無index,對hash join並沒有什麼影響。
一般也是選擇較小的表(內部表)讀入記憶體,進行hash 演算法,根據連線鍵構建成hash table。該錶如果太大的話,會根據當前系統的引數設定,將該錶分piece讀入記憶體構建成hash表。然後外部表中的每行也被讀入記憶體進行hash演算法,得到乙個hash值,對該piece進行比較。
所以hash join的cost 如下:
cost = (outer access cost * number of hash partitions) + inner access cost
上述兩個cost裡面都是先計算出讀入記憶體的小表的access cost,只不過小表對於nested loop來說是outer table,而對於hash join而言是inner table
可見,如果乙個hash記憶體設定的大的話,如果只有乙個piece,那麼cost=內部表與外部表的access cost相加之和,相當的。當然也要算上hash的代價,所以hash應該比nest loop快,但是選擇nested loop還是hash join,一切交給optimizer就可以了。
連線說明:
1.oracle一次只能連線兩個表。不管查詢中有多少個表,
oracle在連線中一次僅能操作兩張表。
2.當執行多個表的連線時,優化器從乙個表開始,將它與另乙個表連線;然後將中間結果與下乙個表連線,以此類推,直到處理完所有表為止。
解答:為了提高查詢效能,oracle 連線中需要選擇合適的驅動表,這是為什麼?
1.以乙個比較兩本字典來做例子:
一本字典有索引目錄(dict a), 一本沒有(dict b)
現在要找出所有a開頭的單詞的異同
那麼比較的時候,你會怎麼比較?
合理的做法應該是以沒有索引的字典dict b開始, 找到a開頭的那一頁, 然後對於每個單詞, 通過使用索引在dict a中找到相應的條目
如果反過來, 效率會相同嗎?
2. 驅動表是在使用多表巢狀連線時,會先全表掃瞄該驅動表,然後驅動表返回的結果集中一行一行去匹配被驅動表(可以利用索引),所以我們會選擇小表做為驅動 表,而被驅動使用索引進行連線。對於基於規則的優化系統,驅動表在from後是有次序設定的,而在基於成本的優化,oracle會選擇最合適的驅動表。
row source(表)之間的連線順序對於查詢的效率有非常大的影響。通過首先訪問特定的表,即將該錶作為驅動表,這樣可以先應用某些限制條件,從而得到乙個 較小的row source,使連線的效率較高,這也就是我們常說的要先執行限制條件的原因。一般是在將表讀入記憶體時,應用where子句中對該錶的限制條件。
應該把資料小的表當做驅動表,也就是把要做驅動的表放在靠近from的地方。
oracle 三種表連線方式
oracle 小知識 1.oracle 檢視表大小 select sum t.bytes 1024 1024 1024 from dba segments t where t.segment name tt tsfr fuzzy abnormal 2.強制走全表掃瞄和索引 full tt conve...
Oracle 表三種連線方式使用介紹 sql優化
1 nested loop 巢狀迴圈 對於被連線的資料子集較小的情況,nested loop連線就是較好的選擇。nested loop就是掃瞄乙個表,每讀到一條記錄,就根據索引去另外乙個表裡面查詢,沒有索引一般就不會是nested loops。一般在nested loop中,驅動表滿足條件結果集不大...
Oracle 三種表連線演算法總結
oracle有三種表連線技術,分別是巢狀連線 合併連線和雜湊連線。巢狀連線把要處理的資料集分為外迴圈 驅動資料來源 和內迴圈 被驅動資料來源 外迴圈只執行一次 先執行 內迴圈執行的次數等於外迴圈執行的資料集個數。這種連線的好處是記憶體使用非常少。如果驅動資料來源有限,且被驅動表在連線列上有相應的索引...