SWAP_JOIN_INPUTS Oracle Hint(处理hash join强制大表(segment_size大)作为被驱动表)

swap_join_inputs是针对哈希连接的hint,它的含义是让优化器交换原哈希连接的驱动表和被驱动表的顺序,即在依然走哈希连接的情况下让原哈希连接的驱动表变被驱动表,让原哈希连接的被驱动表变为驱动表。

注意,在swap_join_inputs hint中指定的目标表应该是原哈希连接中的被驱动表,否则oracle会忽略该hint。

/*+ swap_join_inputs(原哈希连接的被驱动表) */

其使用范例如下:


1

2

select /*+ leading(dept) use_hash(emp) swap_join_intputs(emp) */ * from emp,dept where

emp.deptno=dept.deptno

测试案例:


1

2

3

4

5

6

[email protected]> create table t1 as select from dba_objects where rownum<2;

Table created.

[email protected]> create table t2 as select from dba_objects where rownum<12;

Table created.

[email protected]> create table t3 as select from dba_objects where rownum<22;

Table created.

收集统计信息:


1

2

3

4

5

6

[email protected]> exec dbms_stats.gather_table_stats(ownname => ‘SCOTT‘,tabname => ‘T1‘,estimate_percent => 100,cascade => true,method_opt => ‘for all columns size 1‘,no_invalidate => false);

PL/SQL procedure successfully completed.

[email protected]> exec dbms_stats.gather_table_stats(ownname => ‘SCOTT‘,tabname => ‘T2‘,estimate_percent => 100,cascade => true,method_opt => ‘for all columns size 1‘,no_invalidate => false);

PL/SQL procedure successfully completed.

[email protected]> exec dbms_stats.gather_table_stats(ownname => ‘SCOTT‘,tabname => ‘T3‘,estimate_percent => 100,cascade => true,method_opt => ‘for all columns size 1‘,no_invalidate => false);

PL/SQL procedure successfully completed.

3个表的记录如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[email protected]> select count(*) from t1;

 COUNT(*)

-----------------

1

1 row selected.

[email protected]> select count(*) from t2;

 COUNT(*)

-----------------

       11

1 row selected.

[email protected]> select count(*) from t3;

 COUNT(*)

-----------------

       21

1 row selected.

现在我们来让表T2和T3做哈希连接,由于T3表的记录数比T2表的记录数多,所以这里指定T3为哈希连接的被驱动表:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

select /*+ ordered use_hash(t3) */ t2.object_name,t3.object_type

  2  from t2,t3 where t2.object_id=t3.object_id;

Execution Plan

----------------------------------------------------------

Plan hash value: 1730954469

---------------------------------------------------------------------------

| Id  | Operation   | Name Rows  | Bytes | Cost (%CPU)| Time  |

---------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |  |    11 |   220 |6   (0)| 00:00:01 |

|*  1 |  HASH JOIN   |  |    11 |   220 |6   (0)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| T2   |    11 |   110 |3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| T3   |    21 |   210 |3   (0)| 00:00:01 |

---------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

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

可以看到,上述SQL的执行计划现在走的是哈希连接,并且被驱动表示表T3.

如果我们想让哈希连接的被驱动表由T3变成T2,可以在上述sql加入swap_join_inputs hint:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

select /*+ ordered use_hash(t3) swap_join_inputs(t3) */ t2.object_name,t3.object_type

  2  from t2,t3 where t2.object_id=t3.object_id;

Execution Plan

----------------------------------------------------------

Plan hash value: 1723280936

---------------------------------------------------------------------------

| Id  | Operation   | Name Rows  | Bytes | Cost (%CPU)| Time  |

---------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |  |    11 |   220 |6   (0)| 00:00:01 |

|*  1 |  HASH JOIN   |  |    11 |   220 |6   (0)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| T3   |    21 |   210 |3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| T2   |    11 |   110 |3   (0)| 00:00:01 |

---------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

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

用leading(t3) use_hash(t2)也可以同样达到目的:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

select /*+ leading(t3) use_hash(t2) */ t2.object_name,t3.object_type

  2  from t2,t3 where t2.object_id=t3.object_id;

Execution Plan

----------------------------------------------------------

Plan hash value: 1723280936

---------------------------------------------------------------------------

| Id  | Operation   | Name Rows  | Bytes | Cost (%CPU)| Time  |

---------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |  |    11 |   220 |6   (0)| 00:00:01 |

|*  1 |  HASH JOIN   |  |    11 |   220 |6   (0)| 00:00:01 |

|   2 |   TABLE ACCESS FULL| T3   |    21 |   210 |3   (0)| 00:00:01 |

|   3 |   TABLE ACCESS FULL| T2   |    11 |   110 |3   (0)| 00:00:01 |

---------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

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

由此可见在两个表关联的时候,可以用其他hint代替swap_join_inputs来达到相同的目的:

那么多表关联呢:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

select /*+ ordered use_hash(t3) */ t1.owner,t2.object_name,t3.object_type

  2  from t2,t3,t1 where t2.object_id=t3.object_id and t1.object_type=t3.object_type;

Execution Plan

----------------------------------------------------------

Plan hash value: 98820498

----------------------------------------------------------------------------

| Id  | Operation    | Name Rows  | Bytes | Cost (%CPU)| Time   |

----------------------------------------------------------------------------

|   0 | SELECT STATEMENT    |   | 4 |   120 | 9   (0)| 00:00:01 |

|*  1 |  HASH JOIN    |   | 4 |   120 | 9   (0)| 00:00:01 |

|*  2 |   HASH JOIN    |   |11 |   220 | 6   (0)| 00:00:01 |

|   3 |    TABLE ACCESS FULL| T2   |11 |   110 | 3   (0)| 00:00:01 |

|   4 |    TABLE ACCESS FULL| T3   |21 |   210 | 3   (0)| 00:00:01 |

|   5 |   TABLE ACCESS FULL | T1   | 1 |10 | 3   (0)| 00:00:01 |

----------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - access("T1"."OBJECT_TYPE"="T3"."OBJECT_TYPE")

   2 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID"

可以看到,现在上述sql的执行计划是先由表T2和表T3做哈希连接,然后将他们做哈希连接的连接结果集再和表T1做一次哈希连接。

表T1的记录数为1,表T2的记录数为11,表T3的记录数为21,所以当表的T2和T3做哈希连接时,记录数多的表T3应该是被驱动表,这是因为我们在上述sql中使用了ordered hint和use_hash HINT指定表T3作为表T2和T3连接的时的被驱动表,所以oracle这里选择了表T2和T3做哈希连接,并且选择了表T3作为该哈希连接的被驱动表,这是没有问题的,现在问题在于表T1的记录数仅为1,所以当表T2和T3做哈希连接的结果再和表T1做哈希连接时,表T1应该是驱动表,而不是在上述执行计划里显示的那样作为第二个哈希连接的被驱动表。

使用下面HINT:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

select /*+ ordered use_hash(t3) */ t1.owner,t2.object_name,t3.object_type

  2  from t1,t2,t3 where t2.object_id=t3.object_id and t1.object_type=t3.object_type;

Execution Plan

----------------------------------------------------------

Plan hash value: 38266800

------------------------------------------------------------------------------

| Id  | Operation      | Name Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------

|   0 | SELECT STATEMENT      |      |   4 | 120 |   9   (0)| 00:00:01 |

|*  1 |  HASH JOIN      |      |   4 | 120 |   9   (0)| 00:00:01 |

|   2 |   MERGE JOIN CARTESIAN|      |  11 | 220 |   6   (0)| 00:00:01 |

|   3 |    TABLE ACCESS FULL  | T1   |   1 |  10 |   3   (0)| 00:00:01 |

|   4 |    BUFFER SORT      |      |  11 | 110 |   3   (0)| 00:00:01 |

|   5 |     TABLE ACCESS FULL | T2   |  11 | 110 |   3   (0)| 00:00:01 |

|   6 |   TABLE ACCESS FULL   | T3   |  21 | 210 |   3   (0)| 00:00:01 |

------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID" AND

      "T1"."OBJECT_TYPE"="T3"."OBJECT_TYPE")


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

select /*+ leading(t1) use_hash(t3) */ t1.owner,t2.object_name,t3.object_type

  2  from t1,t2,t3 where t2.object_id=t3.object_id and t1.object_type=t3.object_type;

Execution Plan

----------------------------------------------------------

Plan hash value: 2308542799

----------------------------------------------------------------------------

| Id  | Operation    | Name Rows  | Bytes | Cost (%CPU)| Time   |

----------------------------------------------------------------------------

|   0 | SELECT STATEMENT    |   | 7 |   210 | 9   (0)| 00:00:01 |

|*  1 |  HASH JOIN    |   | 7 |   210 | 9   (0)| 00:00:01 |

|*  2 |   HASH JOIN    |   | 7 |   140 | 6   (0)| 00:00:01 |

|   3 |    TABLE ACCESS FULL| T1   | 1 |10 | 3   (0)| 00:00:01 |

|   4 |    TABLE ACCESS FULL| T3   |21 |   210 | 3   (0)| 00:00:01 |

|   5 |   TABLE ACCESS FULL | T2   |11 |   110 | 3   (0)| 00:00:01 |

----------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

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

   2 - access("T1"."OBJECT_TYPE"="T3"."OBJECT_TYPE")

加入以下hint,就解决:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

SELECT /*+ ordered use_hash(t3) swap_join_inputs(t1) */

 t1.owner, t2.object_name, t3.object_type

  FROM t2, t3, t1

 WHERE t2.object_id = t3.object_id

  5     AND t1.object_type = t3.object_type;

Execution Plan

----------------------------------------------------------

Plan hash value: 3071514789

----------------------------------------------------------------------------

| Id  | Operation    | Name Rows  | Bytes | Cost (%CPU)| Time   |

----------------------------------------------------------------------------

|   0 | SELECT STATEMENT    |   | 4 |   120 | 9   (0)| 00:00:01 |

|*  1 |  HASH JOIN    |   | 4 |   120 | 9   (0)| 00:00:01 |

|   2 |   TABLE ACCESS FULL | T1   | 1 |10 | 3   (0)| 00:00:01 |

|*  3 |   HASH JOIN    |   |11 |   220 | 6   (0)| 00:00:01 |

|   4 |    TABLE ACCESS FULL| T2   |11 |   110 | 3   (0)| 00:00:01 |

|   5 |    TABLE ACCESS FULL| T3   |21 |   210 | 3   (0)| 00:00:01 |

----------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - access("T1"."OBJECT_TYPE"="T3"."OBJECT_TYPE")

   3 - access("T2"."OBJECT_ID"="T3"."OBJECT_ID")

转:http://7642644.blog.51cto.com/7632644/1699902

时间: 2024-07-30 13:47:54

SWAP_JOIN_INPUTS Oracle Hint(处理hash join强制大表(segment_size大)作为被驱动表)的相关文章

oracle表之间的连接之-----&gt;哈希连接(Hash Join)

哈希连接(HASH JOIN)是一种两个表在做表连接时主要依靠哈希运算来得到连接结果集的表连接方法. 对于排序合并连接,如果两个表在施加了目标SQL中指定的谓词条件后得到的结果集很大而且需要排序,则排序合并连接的执行效率一定不高:而对于嵌套循环连接,如果驱动表所对应的驱动结果集的记录数很大,即便在被驱动表的连接列上存在索引,此时使用嵌套循环连接的执行效率也会同样不高.为了解决这个问题,于是ORACLE引进了哈希连接.在ORACLE 10g及其以后的版本中,优化器 (实际上是CBO,因为哈希连接仅

oracle多表连接方式Hash Join Nested Loop Join Merge Join

在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式:        嵌套循环(Nested  Loops (NL))      (散列)哈希连接(Hash Join (HJ))    (归并)排序合并连接(Sort Merge Join (SMJ) ) 二.连接说明:    1.Oracle一次只能连接两个表.不管查询中有多少个表,Oracle 在连接中一次仅能操作两张表.    2.当执行多个表的连接时,优化

oracle 表连接 - hash join 哈希连接

一. hash 连接(哈希连接)原理 指的是两个表连接时, 先利用两表中记录较少的表在内存中建立 hash 表, 然后扫描记录较多的表并探測 hash 表, 找出与 hash 表相匹配的行来得到结果集的表连接方法. 哈希连接仅仅能用于等值连接条件(=). 如果以下的 sql 语句中表 T1 和 T2 的连接方式是哈希连接, T1 是驱动表 select * from T1, T2 where T1.id = T2.id and T1.name = 'David'; oracle 运行过程例如以下

深入理解Oracle表(5):三大表连接方式详解之Hash Join的定义,原理,算法,成本,模式和位图...

Hash Join只能用于相等连接,且只能在CBO优化器模式下.相对于nested loop join,hash join更适合处理大型结果集       Hash Join的执行计划第1个是hash表(build table),第2个探查表(probe table),一般不叫内外表,nested loop才有内外表       Hash表也就是所谓的内表,探查表所谓的外表       两者的执行计划形如:       nested loop           outer table    

NESTED LOOPS &amp; HASH JOIN &amp; SORT MERGE JOIN

表连接方式及使用场合 NESTED LOOP 对于被连接的数据子集较小的情况,nested loop连接是个较好的选择.nested loop就是扫描一个表,每读到一条记录,就根据索引去另一个表里面查找,没有索引一般就不会是 nested loops.一般在nested loop中, 驱动表满足条件结果集不大,被驱动表的连接字段要有索引,这样就走nstedloop.如果驱动表返回记录太多,就不适合nested loops了.如果连接字段没有索引,则适合走hash join,因为不需要索引. 可用

hash join

hash join是oracle里面一个非常强悍的功能,当做hash join时,oracle会选择一个表作为驱动表,先根据过滤条件排除不必要的数据,然后将结果集做成hash表,放入进程的hash area,接着扫描第二张表,将行的键值做hash运算,到内存的hash表里面去探测,如果探测成功,就返回数据,否则这行就丢弃掉这个是最基本的解释,实际情况中,考虑到单个进程PGA的大小,oracle不会让进程任意的消耗OS内存,hash area是有一定限制的,所以在oracle中,hash也有三种模

Oracle 表的连接方式(2)-----HASH JOIN的基本机制3

HASH JOIN的模式 hash join有三种工作模式,分别是optimal模式,onepass模式和multipass模式,分别在v$sysstat里面有对应的统计信息: SQL> select name, value from v$sysstat where name like '%workarea executions%'; optimal模式 optimal模式就是从build table上获取的结果集比较小,可以把整个hash table都建立在用户可以使用的内存区域里.下面这张图

Oracle 表的连接方式(2)-----HASH JOIN的基本机制1

我们对hash join的常见误解,一般包括两个: 第一个误解:是我们经常以为hash join需要对两个做join的表都做全表扫描 第二个误解:是经常以为hash join会选择比较小的表做build table 纠正第一个误解: 我们经常以为hash join需要对两个做join的表都做全表扫描,但实际情况HASH JOIN是不会限制SQL的访问方法的.我们用下面的测试来验证: --创建测试表probe_tab: SQL> create table probe_tab 2 initrans

Oracle 表的连接方式(2)-----HASH JOIN的基本机制2

Hash算法原理 对于什么是Hash算法原理?这个问题有点难度,不是很好说清楚,来做一个比喻吧:我们有很多的小猪,每个的体重都不一样,假设体重分布比较平均(我们考虑到公斤级别),我们按照体重来分,划分成100个小猪圈. 然后把每个小猪,按照体重赶进各自的猪圈里,记录档案. 好了,如果我们要找某个小猪怎么办呢?我们需要每个猪圈,每个小猪的比对吗? 当然不需要了. 我们先看看要找的这个小猪的体重,然后就找到了对应的猪圈了. 在这个猪圈里的小猪的数量就相对很少了. 我们在这个猪圈里就可以相对快的找到我