在查看SQL執行計畫時,我們會發現表的串連方式有多種,本文對錶的串連方式進行介紹以便更好看懂執行計畫和理解sql執行原理。
一、串連方式:
嵌套迴圈(Nested Loops (NL))
(散列)雜湊串連(Hash Join (HJ))
(歸併)排序合并串連(Sort Merge Join (SMJ) )
二、串連說明:
1.Oracle一次只能串連兩個表。不管查詢中有多少個表,Oracle在串連中一次僅能操作兩張表。
2.當執行多個表的串連時,最佳化器從一個表開始,將它與另一個表串連;然後將中間結果與下一個表串連,以此類推,直到處理完所有表為止。
三、表串連詳解:
1. 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。
要點如下:
1)對於被串連的資料子集較小的情況,嵌套迴圈串連是個較好的選擇
2)使用USE_NL(table_name1 table_name2)可是強制CBO 執行嵌套迴圈串連
3)Nested loop一般用在串連的表中有索引,並且索引選擇性較好的時候
4)OIN的順序很重要,驅動表的記錄集一定要小,返回結果集的回應時間是最快的。
5)Nested loops 工作方式是從一張表中讀取資料,訪問另一張表(通常是索引)來做匹配,nested loops適用的場合是當一個關聯表比較小的時候,效率會更高。
例子如下:
SQL> create table t as select * from user_tables;
表已建立。
SQL> create index index_t on t(table_name);
索引已建立。
SQL> create table t1 as select * from user_tables where table_name like '%ACCESS%';
表已建立。
SQL> create index index_t1 on t1(table_name);
索引已建立。
SQL> begin
2 dbms_stats.gather_table_stats(ownname =>'TEST' ,tabname =>'T');
3 end;
4 /
PL/SQL 過程已成功完成。
SQL> begin
2 dbms_stats.gather_table_stats(ownname =>'TEST' ,tabname =>'T');
3 end;
4 /
由於t1表記錄很小作驅動表且t表的建有索引,適合NL,執行計畫如下:
SQL> set wrap off;
SQL> set autotrace traceonly;
SQL> select a.table_name,b.table_name from t a,t1 b
2 where a.table_name = b.table_name;
已選擇8行。
執行計畫
----------------------------------------------------------
Plan hash value: 3579965632
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 280 | 4 (0)| 00:00:01
| 1 | NESTED LOOPS | | 8 | 280 | 4 (0)| 00:00:01
| 2 | INDEX FAST FULL SCAN| INDEX_T | 1921 | 34578 | 4 (0)| 00:00:01
|* 3 | INDEX RANGE SCAN | INDEX_T1 | 1 | 17 | 0 (0)| 00:00:01
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."TABLE_NAME"="B"."TABLE_NAME")
Note
-----
- dynamic sampling used for this statement (level=2)
統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
18 consistent gets
0 physical reads
0 redo size
807 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
8 rows processed
SQL> select a.table_name,b.table_name from t1 a,t b
2 where a.table_name = b.table_name;
已選擇8行。
執行計畫
----------------------------------------------------------
Plan hash value: 3579965632
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 280 | 4 (0)| 00:00:01
| 1 | NESTED LOOPS | | 8 | 280 | 4 (0)| 00:00:01
| 2 | INDEX FAST FULL SCAN| INDEX_T | 1921 | 34578 | 4 (0)| 00:00:01
|* 3 | INDEX RANGE SCAN | INDEX_T1 | 1 | 17 | 0 (0)| 00:00:01
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."TABLE_NAME"="B"."TABLE_NAME")
Note
-----
- dynamic sampling used for this statement (level=2)
統計資訊
----------------------------------------------------------
4 recursive calls
0 db block gets
23 consistent gets
0 physical reads
0 redo size
807 bytes sent via SQL*Net to client
415 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
8 rows processed
------------------------------------------------------
假定我們利用提示改變的表的串連順序
ORACLE的解析器按照從右至左的順序處理FROM子句中的表名,FROM子句中寫在最後的表(基礎資料表 driving table)將被最先處理,在FROM子句中包含多個表的情況下,你必須選擇記錄條數最少的表作為基礎資料表。如果有3個以上的表串連查詢, 那就需要選擇交叉表(intersection table)作為基礎資料表, 交叉表是指那個被其他表所引用的表.