use_nl,use_hash,use_merge的3种连接方式驱动与被驱动关系
2014-05-31 21:41
190 查看
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
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')); 就会发现真正的原因是预估值与实际值的问题相差过大导致的; 在这种情况下执行计划的绑定是比较实用和有效的;
相关文章推荐
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 表与表间的连接方式 Nest loop, Hash join and Sort merge join
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- oracle sql调优学习笔记(三)表的连接方式:NESTED LOOP、HASH JOIN、SORT MERGE JOIN
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP (转David)
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP .
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP【1】
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP【2】
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- use_nl,use_merge,use_hash
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP【3】
- 多表连接的三种方式详解 HASH JOIN MERGE JOIN NESTED LOOP