最近认真参加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 |
--------------------------------------------------------------------------------------