Oracle表連線操作——Merge Sort Join(合併排序連線)
關係型資料庫並不是最早出現的資料庫表現形式,之前還存在層次、網狀資料庫結構。隨著關係型資料庫的出現,以資料表的方式進行資訊留存的方案迅速發展起來。關係型資料庫的重要元素包括資料表和表連線,藉助各種型別的表連線,可以將平鋪直敘的資訊加以組裝拼接。
1、Merge Sort Join原理機制
Nest Loop Join巢狀迴圈是一種比較古老的連線匹配方式,特點是透過兩層的迴圈結構,將符合條件的資料行整理出來。巢狀迴圈的最大缺陷之一,就是伴隨著驅動表被驅動表之間的選擇,以及大量隨機讀現象。
Merge Sort Join連線的優勢就是可以一定程度上減少隨機讀的情況。合併排序連線的最大特徵是在一次掃描的同時,就判斷連線。不會像Nest Loop Join那樣頻繁的進行資料讀取。使用這種方式的前提,就是連線的兩個資料集合必須按照連線列的順序進行排序。具體操作流程如下:
ü 對Merge Sort Join連線而言,不存在驅動表和被驅動表的問題。兩邊的資料集合沒有順序區別,都要進行排序操作;
ü 根據Oracle排序規則和方法,按照連線列的順序對兩個資料集合進行排序;
ü 依次對兩邊的資料集合進行掃描,由於已經是排序過得結果,可以直接確定連線條件是否匹配;
ü 確定進行連線的兩端資料行,再依據篩選列的要求獲取資料;
下面是一個進行Merge Sort Join的執行計劃:
//使用Merge Sort Join方法
SQL> select /*+use_merge(segs,tabs)*/* from segs, tabs where segs.segment_name=tabs.table_name;
已選擇865行。
執行計劃
----------------------------------------------------------
Plan hash value: 3475644097
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 990 | 354K| | 144 (2)| 00:00:02 |
| 1 | MERGE JOIN | | 990 | 354K| | 144 (2)| 00:00:02 |
| 2 | SORT JOIN | | 968 | 229K| 712K| 65 (2)| 00:00:01 |
| 3 | TABLE ACCESS FULL| TABS | 968 | 229K| | 11 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 2267 | 274K| 824K| 79 (2)| 00:00:01 |
| 5 | TABLE ACCESS FULL| SEGS | 2267 | 274K| | 13 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
filter("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
統計資訊
----------------------------------------------------------
2010 recursive calls
0 db block gets
378 consistent gets
0 physical reads
0 redo size
72346 bytes sent via SQL*Net to client
1003 bytes received via SQL*Net from client
59 SQL*Net roundtrips to/from client
10 sorts (memory)
0 sorts (disk)
865 rows processed
//使用巢狀迴圈;
SQL> select /*+use_nl(segs,tabs)*/* from segs, tabs where segs.segment_name=tabs.table_name;
已選擇865行。
執行計劃
----------------------------------------------------------
Plan hash value: 840690564
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 990 | 354K| 11075 (1)| 00:02:13 |
| 1 | NESTED LOOPS | | 990 | 354K| 11075 (1)| 00:02:13 |
| 2 | TABLE ACCESS FULL| TABS | 968 | 229K| 11 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| SEGS | 1 | 124 | 11 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
統計資訊
----------------------------------------------------------
1930 recursive calls
0 db block gets
43978 consistent gets
0 physical reads
0 redo size
70556 bytes sent via SQL*Net to client
1003 bytes received via SQL*Net from client
59 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
865 rows processed
上面程式碼示例中給出了兩個執行計劃,給我們如下的資訊。
首先,我們觀察使用use_merge提示的SQL,在Hint的作用下,CBO生成的執行計劃中使用Merge Sort Join連線方式。在執行計劃中Oracle對兩個資料表進行Sort操作,之後對排序過的結果進行Merge連線。其中Oracle對兩個資料表進行的都是全表掃描操作。
另一個執行計劃是使用use_nl控制的Nest Loop Join連線方式。中間同樣也是沒有使用索引等方式。其中,產生了大量邏輯讀。見下表對比:
對比專案 |
Merge Sort Join |
Nest Loop Join |
邏輯讀consistent gets |
378 |
43978 |
排序空間sort |
10 |
6 |
透過資料資訊的對比,我們可以明顯的看出兩個相同結果集合的SQL,由於不同的連線方式而帶來的差異。Merge Sort Join可以大大消除由於Nest Loop Join帶來的隨機讀過多的情況。而由於進行的排序操作,Merge Sort Join也要付出相應的排序空間損耗。
2、Merge Sort Join與排序空間
對Oracle熟悉的朋友們通常對Sort和Group操作是比較敏感的。Sort和Group by都是需要單獨對資料集進行的操作,要消耗額外的CPU和記憶體資源。CPU資源主要消耗在演算法排序和結果集合整合上。而記憶體資源的消耗更加需要關注,排序操作要在專門的PGA排序區內完成。如果PGA中特定的排序大小(pga_aggregat_target:sort_area_size)不足以進行排序操作,也就是說需要排序分組的資料集合特別大的時候,Oracle需要呼叫Temp表空間的容量來進行操作。
這也就是問題的所在。Temp表空間資料儲存位於磁碟中,速度與記憶體相差很多。所以,當進行排序操作的資料集合很大,會出現效能急劇的下降可能。在實際業務場景中,對海量資料集合的處理、Data Warehouse應用的操作,都可能出現這種情況。
回到Merge Sort Join來,就可以理解這種連線方式的缺陷之處了。要進行Merge Sort Join,其中的Sort過程不可避免。而使用Sort操作帶來的優勢就是不需要進行過多的隨機讀。在資料集合量很大的時候,Merge Sort Join的效率可能會很差。
3、對索引路徑的借用
在Nest Loop Join中,對連線列進行索引處理,可以很大程度上提升執行計劃效率,減少隨機讀的數量。道理就是借用了索引排序這個現實。而Merge Sort Join對索引的應用效果遠不如Nest Loop Join。
索引環境構建:
//索引構建
SQL> create index idx_tabs_name on tabs(table_name);
Index created
SQL> create index idx_segs_name on segs(segment_name);
Index created
SQL> exec dbms_stats.gather_table_stats(user,'SEGS',cascade => true);
PL/SQL procedure successfully completed
SQL> exec dbms_stats.gather_table_stats(user,'TABS',cascade => true);
PL/SQL procedure successfully completed
執行計劃如下:
SQL> explain plan for select /*+use_merge(tabs,segs)*/* from segs,tabs where segs.segment_name=tabs.table_name;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 3475644097
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 990 | 354K| | 144 (2)| 00:00:
| 1 | MERGE JOIN | | 990 | 354K| | 144 (2)| 00:00:
| 2 | SORT JOIN | | 968 | 229K| 712K| 65 (2)| 00:00:
| 3 | TABLE ACCESS FULL| TABS | 968 | 229K| | 11 (0)| 00:00:
|* 4 | SORT JOIN | | 2267 | 274K| 824K| 79 (2)| 00:00:
| 5 | TABLE ACCESS FULL| SEGS | 2267 | 274K| | 13 (0)| 00:00:
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
filter("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
18 rows selected
由於Merge Sort Join本身就帶有排序的特性,而且返回的結果集合中包括所有欄位。所以通常的執行計劃中,即使連線列存在索引,也不會進入到執行計劃中。除非進行一些特定列處理。
SQL> explain plan for select /*+use_merge(tabs,segs)*/segs.segment_name,tabs.table_name from segs,tabs where segs.segment_name=tabs.table_name;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 712326860
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 990 | 37620 | 9 (23)| 00
| 1 | MERGE JOIN | | 990 | 37620 | 9 (23)| 00
| 2 | SORT JOIN | | 968 | 17424 | 4 (25)| 00
| 3 | INDEX FAST FULL SCAN| IDX_TABS_NAME | 968 | 17424 | 3 (0)| 00
|* 4 | SORT JOIN | | 2267 | 45340 | 5 (20)| 00
| 5 | INDEX FAST FULL SCAN| IDX_SEGS_NAME | 2267 | 45340 | 4 (0)| 00
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
filter("SEGS"."SEGMENT_NAME"="TABS"."TABLE_NAME")
18 rows selected
在對返回結果進行處理的情況下,索引路徑會出現的。
4、結論
Merge Sort Join是一種古老經典的排序模型,類似於資料結構時代的合併排序演算法。Merge Sort Join引入的最大優勢是避免同Nest Loop Join類似的大量隨機讀現象,但是同時也引入了Sort空間變化的問題。
隨著海量資料處理場景的增多,Merge Sort Join暴露出缺陷的機會越來越多。而Nest Loop Join的大量隨機讀問題,也是可以透過索引等常規手段加以最佳化。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28371090/viewspace-1184844/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 排序合併連線(sort merge join)的原理排序
- Oracle的表連線方法(一)排序合併連線Oracle排序
- 表的連線方式:NESTED LOOP、HASH JOIN、SORT MERGE JOIN(轉)OOP
- Oracle表連線操作——Hash Join(雜湊連線)下Oracle
- Oracle表連線操作——Hash Join(雜湊連線)上Oracle
- 微課sql最佳化(16)、表的連線方法(5)-關於Merge Join(排序合連線)SQL排序
- 兩表連線三:合併連線
- Oracle(+)連線與Join連線Oracle
- Nested loops、Hash join、Sort merge join(三種連線型別原理、使用要點)OOP型別
- mysql INNER JOIN、LEFT JOIN、RIGHT JOIN;內連線(等值連線)、左連線、右連線MySql
- 排序和表連線排序
- Oracle 的 hash join連線方式Oracle
- Oracle 表連線Oracle
- java操作Oracle 方式一 ( 連線-》操作-》斷開連線 )JavaOracle
- Oracle 表連線方式詳解(外連結、內連線、自連線)Oracle
- DBA ORACLE連線操作Oracle
- sql 連線查詢例項(left join)三表連線查詢SQL
- Oracle 連線因式分解(Join Factorization)Oracle
- Oracle 內外連線 join 總結Oracle
- LEFT JOIN 和JOIN 多表連線
- 表連線 join和(+)、union和uion allUI
- 多表連線的三種方式詳解 hash join、merge join、 nested loopOOP
- ORACLE 表連線方式Oracle
- oracle表連線方式Oracle
- Oracle的表連線方法(三)雜湊連線Oracle
- SQL 經典回顧:JOIN 表連線操作不完全指南SQL
- 原地歸併排序 Merge Sort in place排序
- 【SQL】表連線 --半連線SQL
- 水煮oracle31----連線查詢&合併查詢Oracle
- MySql的join(連線)查詢 (三表 left join 寫法)MySql
- 外連線(outer join)示例
- 【TUNE_ORACLE】列出走了錯誤的排序合併連線的SQL參考Oracle排序SQL
- Oracle左連線,右連線Oracle
- DB2 SQL之行合併(連線)DB2SQL
- Oracle的表連線方法(二)巢狀迴圈連線Oracle巢狀
- 排序演算法之「歸併排序(Merge Sort)」排序演算法
- Oracle查詢轉換(三)外連線檢視合併Oracle
- 表連線方式及使用場合