use_nl,use_hash,use_merge的3种连接方式驱动与被驱动关系

SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE    11.2.0.3.0      Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production

--use_nl,use_hash,use_merge的3种连接方式驱动与被驱动关系

一.HASH连接方式

--建一个小表和一个大一些的表
SQL> create table t1 as select * from dba_objects where rownum<11;

Table created.

SQL> create table t2 as select * from dba_objects;

Table created.

SQL> select count(1) from t1;

  COUNT(1)
----------
        10

SQL> select count(1) from t2;

  COUNT(1)
----------
     75211
    
--试验HASH,可以看出hash是存在驱动与被驱动关系,驱动表适合于两表间较小的一个,耗用更少的排序开销;     
SQL> select /*+ leading(t2) use_hash(t2,t1) */t1.status,t2.status
  2  from t1,t2
  3  where t1.object_id=t2.object_id;

STATUS  STATUS
------- -------
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID

10 rows selected.

--看到排序区中排序的开销为3439K;
SQL> @allstat

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  315bd4pgdyt86, child number 1
-------------------------------------
select /*+ leading(t2) use_hash(t2,t1) */t1.status,t2.status from t1,t2
where t1.object_id=t2.object_id

Plan hash value: 2959412835

-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     10 |00:00:00.08 |    1078 |   1071 |       |       |          |
|*  1 |  HASH JOIN         |      |      1 |     10 |     10 |00:00:00.08 |    1078 |   1071 |  3439K|  1573K| 5617K (0)|
|   2 |   TABLE ACCESS FULL| T2   |      1 |  79628 |  75211 |00:00:00.02 |    1074 |   1071 |       |       |          |
|   3 |   TABLE ACCESS FULL| T1   |      1 |     10 |     10 |00:00:00.01 |       4 |      0 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)


25 rows selected.

--而T1表为驱动表时,排序的开销为1206K比上面的3439K小得多;
SQL> select /*+ leading(t1) use_hash(t2,t1) */t1.status,t2.status
  2  from t1,t2
  3  where t1.object_id=t2.object_id;

STATUS  STATUS
------- -------
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID
VALID   VALID

10 rows selected.

SQL> @allstat

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  3zc11bg9gdq31, child number 1
-------------------------------------
select /*+ leading(t1) use_hash(t2,t1) */t1.status,t2.status from t1,t2
where t1.object_id=t2.object_id

Plan hash value: 1838229974

-------------------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     10 |00:00:00.08 |    1078 |   1071 |       |       |          |
|*  1 |  HASH JOIN         |      |      1 |     10 |     10 |00:00:00.08 |    1078 |   1071 |  1206K|  1206K| 1126K (0)|
|   2 |   TABLE ACCESS FULL| T1   |      1 |     10 |     10 |00:00:00.01 |       3 |      0 |       |       |          |
|   3 |   TABLE ACCESS FULL| T2   |      1 |  79628 |  75211 |00:00:00.03 |    1075 |   1071 |       |       |          |
-------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)


25 rows selected.

--而ORACLE在预估COST时第一类的COST也是大于第2类,也就是默认O是会采用第2种方式;
--第1类的COST为419,而第2类的COST预估为305;
SQL> set auto traceonly
SP2-0158: unknown SET autocommit option "traceonly"
Usage: SET AUTO[COMMIT] { OFF | ON | IMM[EDIATE] | n }
SQL> set autot traceonly exp
SQL> 
SQL> select /*+ leading(t2) use_hash(t2,t1) */t1.status,t2.status
  2  from t1,t2
  3  where t1.object_id=t2.object_id;

Execution Plan
----------------------------------------------------------
Plan hash value: 2959412835

-----------------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    10 |   360 |       |   419   (1)| 00:00:06 |
|*  1 |  HASH JOIN         |      |    10 |   360 |  2336K|   419   (1)| 00:00:06 |
|   2 |   TABLE ACCESS FULL| T2   | 79628 |  1399K|       |   301   (1)| 00:00:04 |
|   3 |   TABLE ACCESS FULL| T1   |    10 |   180 |       |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)

SQL> select /*+ leading(t1) use_hash(t2,t1) */t1.status,t2.status
  2  from t1,t2
  3  where t1.object_id=t2.object_id;

Execution Plan
----------------------------------------------------------
Plan hash value: 1838229974

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    10 |   360 |   305   (1)| 00:00:04 |
|*  1 |  HASH JOIN         |      |    10 |   360 |   305   (1)| 00:00:04 |
|   2 |   TABLE ACCESS FULL| T1   |    10 |   180 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| T2   | 79628 |  1399K|   301   (1)| 00:00:04 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)
   
--HASH连接方式默认当然是采用后一种COST较小那类;
SQL> select t1.status,t2.status
  2  from t1,t2
  3  where t1.object_id=t2.object_id;

Execution Plan
----------------------------------------------------------
Plan hash value: 1838229974

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    10 |   360 |   305   (1)| 00:00:04 |
|*  1 |  HASH JOIN         |      |    10 |   360 |   305   (1)| 00:00:04 |
|   2 |   TABLE ACCESS FULL| T1   |    10 |   180 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| T2   | 79628 |  1399K|   301   (1)| 00:00:04 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)

   
二.排序合并连接方式
--可以看到无论是哪种表排在前面先执行,其开销都是一样的;也就是说明merge方式是不存在驱动与被驱动的区别关系 ;
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  2yw072zjb9h5b, child number 1
-------------------------------------
select /*+ leading(t1) use_merge(t2,t1) */t1.status,t2.status from
t1,t2 where t1.object_id=t2.object_id

Plan hash value: 412793182

--------------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |     10 |00:00:00.06 |    1077 |   1071 |       |       |          |
|   1 |  MERGE JOIN         |      |      1 |     10 |     10 |00:00:00.06 |    1077 |   1071 |       |       |          |
|   2 |   SORT JOIN         |      |      1 |     10 |     10 |00:00:00.01 |       3 |      0 |  2048 |  2048 | 2048  (0)|
|   3 |    TABLE ACCESS FULL| T1   |      1 |     10 |     10 |00:00:00.01 |       3 |      0 |       |       |          |
|*  4 |   SORT JOIN         |      |     10 |  79628 |     10 |00:00:00.06 |    1074 |   1071 |  2675K|   740K| 2377K (0)|
|   5 |    TABLE ACCESS FULL| T2   |      1 |  79628 |  75211 |00:00:00.02 |    1074 |   1071 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
       filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)


28 rows selected.

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  csjsgn0hh4dr6, child number 1
-------------------------------------
select /*+ leading(t2) use_merge(t2,t1) */t1.status,t2.status from
t1,t2 where t1.object_id=t2.object_id

Plan hash value: 1792967693

--------------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |     10 |00:00:00.09 |    1077 |   1071 |       |       |          |
|   1 |  MERGE JOIN         |      |      1 |     10 |     10 |00:00:00.09 |    1077 |   1071 |       |       |          |
|   2 |   SORT JOIN         |      |      1 |  79628 |     54 |00:00:00.09 |    1074 |   1071 |  2675K|   740K| 2377K (0)|
|   3 |    TABLE ACCESS FULL| T2   |      1 |  79628 |  75211 |00:00:00.02 |    1074 |   1071 |       |       |          |
|*  4 |   SORT JOIN         |      |     54 |     10 |     10 |00:00:00.01 |       3 |      0 |  2048 |  2048 | 2048  (0)|
|   5 |    TABLE ACCESS FULL| T1   |      1 |     10 |     10 |00:00:00.01 |       3 |      0 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")
       filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)

三.嵌套循环连接方式是影响最为明显的,buffers数相差了10倍之多;

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  35g7vtpc63s04, child number 0
-------------------------------------
select /*+ leading(t1) use_nl(t2,t1) */t1.status,t2.status from t1,t2
where t1.object_id=t2.object_id

Plan hash value: 1967407726

----------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     10 |00:00:00.11 |   10745 |  10710 |
|   1 |  NESTED LOOPS      |      |      1 |     10 |     10 |00:00:00.11 |   10745 |  10710 |
|   2 |   TABLE ACCESS FULL| T1   |      1 |     10 |     10 |00:00:00.01 |       4 |      0 |
|*  3 |   TABLE ACCESS FULL| T2   |     10 |      1 |     10 |00:00:00.11 |   10741 |  10710 |
----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)
   
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  1a5dw45kqph9p, child number 0
-------------------------------------
select /*+ leading(t2) use_nl(t2,t1) */t1.status,t2.status from t1,t2
where t1.object_id=t2.object_id

Plan hash value: 4016936828

----------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     10 |00:00:00.93 |     226K|   1071 |
|   1 |  NESTED LOOPS      |      |      1 |     10 |     10 |00:00:00.93 |     226K|   1071 |
|   2 |   TABLE ACCESS FULL| T2   |      1 |  79628 |  75211 |00:00:00.06 |    1075 |   1071 |
|*  3 |   TABLE ACCESS FULL| T1   |  75211 |      1 |     10 |00:00:00.74 |     225K|      0 |
----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter("T1"."OBJECT_ID"="T2"."OBJECT_ID")

Note
-----
   - dynamic sampling used for this statement (level=2)


25 rows selected.

        
小结:从以上可看出,影响大到小的顺序为nl->hash->merge(不影响); 
应用:日常工作环境中经常可看到,由于nl方式不当而应使用hash的案例,毕竟NL对数据量的大小影响是最为敏感;
而ORACLE选择NL方式并没有错,错就错在预估值那里,所以当用explain plan for....,autot等方式看并不能看出问题;
当通过running time的统计信息收集然后select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
就会发现真正的原因是预估值与实际值的问题相差过大导致的;
在这种情况下执行计划的绑定是比较实用和有效的;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值