Oracle 三種表關聯方式的總結, 使用hint來驗證
最近認真參加Dataguru的Oracle培訓,正經學了一些東西,有時間就整理一下放到這裡,以便以後學習。
今天總結一下三種表關聯方式的適用場景。
1. Nested Loop
原理:從外部表中拿資料,去內部表中去比對
適用場景:
1)關聯中有一個表比較小
2)被關聯表的關聯欄位上有索引
3)索引的鍵值重複率不高
例子:t表為大表,d表為小表,t上有索引。
SQL> create table d as select * from dba_objects where rownum<100;
SQL> select * from t, d where t.object_id=d.object_id;
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 31482 | 102 (0)| 00:00:02 |
| 1 | NESTED LOOPS | | 99 | 31482 | 102 (0)| 00:00:02 |
| 2 | TABLE ACCESS FULL | D | 99 | 22275 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| T | 1 | 93 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | T_PK | 1 | | 0 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
相同sql使用Hash Join的結果:
SQL> select /*+ use_hash(t d) */ * from t,d where t.object_id=d.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 68162843
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 31482 | 172 (2)| 00:00:03 |
|* 1 | HASH JOIN | | 99 | 31482 | 172 (2)| 00:00:03 |
| 2 | TABLE ACCESS FULL| D | 99 | 22275 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T | 53023 | 4815K| 168 (2)| 00:00:03 |
---------------------------------------------------------------------------
相同sql使用Merge Join的結果:
SQL> select /*+ use_merge(t d) */ * from t,d where t.object_id=d.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1512134595
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 31482 | 1008 (1)| 00:00:13 |
| 1 | MERGE JOIN | | 99 | 31482 | 1008 (1)| 00:00:13 |
| 2 | TABLE ACCESS BY INDEX ROWID| T | 53023 | 4815K| 1004 (1)| 00:00:13 |
| 3 | INDEX FULL SCAN | T_PK | 53023 | | 112 (1)| 00:00:02 |
|* 4 | SORT JOIN | | 99 | 22275 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL | D | 99 | 22275 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
2.Hash Join
原理:優化器掃描小表(或資料來源),利用連線鍵(也就是根據連線欄位計算hash 值)在記憶體中建立hash表,然後掃描大表,每讀到一條記錄就來探測hash表一次,找出與hash表匹配的行。
適用場景:
1)一個大表一個小表的關聯
2)表上沒有索引 (關聯表上沒有索引,CBO不會考慮使用Nested Loop)
3)返回結果集比較大
例子:去掉t表索引
SQL> alter table t drop primary key;
Table altered.
SQL> select * from t, d where t.object_id=d.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 68162843
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 31482 | 172 (2)| 00:00:03 |
|* 1 | HASH JOIN | | 99 | 31482 | 172 (2)| 00:00:03 |
| 2 | TABLE ACCESS FULL| D | 99 | 22275 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T | 53023 | 4815K| 168 (2)| 00:00:03 |
---------------------------------------------------------------------------
相同sql使用Nested Loop
SQL> select /*+ use_nl(t d) */ * from t,d where t.object_id=d.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 3796256697
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 31482 | 16448 (2)| 00:03:18 |
| 1 | NESTED LOOPS | | 99 | 31482 | 16448 (2)| 00:03:18 |
| 2 | TABLE ACCESS FULL| D | 99 | 22275 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| T | 1 | 93 | 166 (2)| 00:00:02 |
---------------------------------------------------------------------------
相同sql使用Merge Join
QL> select /*+ use_merge(t d) */ * from t,d where t.object_id=d.object_id;
xecution Plan
---------------------------------------------------------
lan hash value: 3365178606
-----------------------------------------------------------------------------------
Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
0 | SELECT STATEMENT | | 99 | 31482 | | 1311 (1)| 00:00:16 |
1 | MERGE JOIN | | 99 | 31482 | | 1311 (1)| 00:00:16 |
2 | SORT JOIN | | 99 | 22275 | | 4 (25)| 00:00:01 |
3 | TABLE ACCESS FULL| D | 99 | 22275 | | 3 (0)| 00:00:01 |
* 4 | SORT JOIN | | 53023 | 4815K| 12M| 1307 (1)| 00:00:16 |
5 | TABLE ACCESS FULL| T | 53023 | 4815K| | 168 (2)| 00:00:03 |
-----------------------------------------------------------------------------------
3.Merge Join
原理:將兩個結果集分別排序,對排序後的結果集進行連線
適用場景:當結果集已經排過序
例子:先排序,再關聯
SQL> select * from (select * from t order by object_id) t, (select * from d order by object_id) d
2 where t.object_id=d.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 2926044903
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 43758 | | 1311 (1)| 00:00:16 |
| 1 | MERGE JOIN | | 99 | 43758 | | 1311 (1)| 00:00:16 |
| 2 | VIEW | | 53023 | 10M| | 1307 (1)| 00:00:16 |
| 3 | SORT ORDER BY | | 53023 | 4815K| 12M| 1307 (1)| 00:00:16 |
| 4 | TABLE ACCESS FULL| T | 53023 | 4815K| | 168 (2)| 00:00:03 |
|* 5 | SORT JOIN | | 99 | 22275 | | 4 (25)| 00:00:01 |
| 6 | TABLE ACCESS FULL | D | 99 | 22275 | | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
相同sql使用Nested Loop
SQL> select /*+ use_nl(t d) */ * from (select * from t order by object_id) t, (select * from d order by object_id) d
2 where t.object_id=d.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1008542415
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 43758 | | 59577 (1)| 00:11:55 |
| 1 | SORT ORDER BY | | 99 | 43758 | | 59577 (1)| 00:11:55 |
| 2 | NESTED LOOPS | | 99 | 43758 | | 59576 (1)| 00:11:55 |
| 3 | VIEW | | 53023 | 10M| | 1307 (1)| 00:00:16 |
| 4 | SORT ORDER BY | | 53023 | 4815K| 12M| 1307 (1)| 00:00:16 |
| 5 | TABLE ACCESS FULL| T | 53023 | 4815K| | 168 (2)| 00:00:03 |
|* 6 | TABLE ACCESS FULL | D | 1 | 225 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
相同sql使用Hash Join
SQL> select /*+ use_hash(t d) */ * from (select * from t order by object_id) t, (select * from d order by object_id) d
2 where t.object_id=d.object_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 3786187078
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 99 | 43758 | | 1312 (1)| 00:00:16 |
| 1 | SORT ORDER BY | | 99 | 43758 | | 1312 (1)| 00:00:16 |
|* 2 | HASH JOIN | | 99 | 43758 | | 1311 (1)| 00:00:16 |
| 3 | TABLE ACCESS FULL | D | 99 | 22275 | | 3 (0)| 00:00:01 |
| 4 | VIEW | | 53023 | 10M| | 1307 (1)| 00:00:16 |
| 5 | SORT ORDER BY | | 53023 | 4815K| 12M| 1307 (1)| 00:00:16 |
| 6 | TABLE ACCESS FULL| T | 53023 | 4815K| | 168 (2)| 00:00:03 |
--------------------------------------------------------------------------------------