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

时间:2022-08-27 20:35:02

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
SCOTT@ORA12C> create table t1 as select from dba_objects where rownum<2;
Table created.
SCOTT@ORA12C> create table t2 as select from dba_objects where rownum<12;
Table created.
SCOTT@ORA12C> create table t3 as select from dba_objects where rownum<22;
Table created.

收集统计信息:

1
2
3
4
5
6
SCOTT@ORA12C> 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.
SCOTT@ORA12C> 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.
SCOTT@ORA12C> 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
SCOTT@ORA12C> select count(*) from t1;
 COUNT(*)
-----------------
1
1 row selected.
SCOTT@ORA12C> select count(*) from t2;
 COUNT(*)
-----------------
       11
1 row selected.
SCOTT@ORA12C> 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

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

  1. Bullet&colon;关于ORACLE中的HASH JOIN的参数变化

    Oracle在7.3引入了hash join. 但是在Oracle 10g及其以后的Oracle数据库版本中,优化器,实际是CBO,也是因为HASH JOIN仅适用于CBO,在解析目标SQL时是否考虑 ...

  2. Oracle 三种连接方式 NESTED LOOP HASH JOIN SORT MERGE JOIN

    NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大( ...

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

    在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式:        嵌套循环(Nested  Loops (NL) ...

  4. OLAP 大表和小表并行hash join

    一个表50MB 一个表10GB 50M表做驱动表,放在PGA里 这时候慢在对对 10g 的全表扫描 对10个G扫描块 需要开并行 我有这样一个算法 一个进程 读 50mb 8进程 来 扫描 10gb ...

  5. oracle 表连接 - hash join 哈希连接

    一. hash 连接(哈希连接)原理 指的是两个表连接时, 先利用两表中记录较少的表在内存中建立 hash 表, 然后扫描记录较多的表并探測 hash 表, 找出与 hash 表相匹配的行来得到结果集 ...

  6. 品味性能之道&lt&semi;十&gt&semi;:Oracle Hint

    Hint 是Oracle 提供的一种SQL语法,它允许用户在SQL语句中插入相关的语法,从而影响SQL的执行方式. 因为Hint的特殊作用,所以对于开发人员不应该在代码中使用它,Hint 更像是Ora ...

  7. Oracle hint之ORDERED和USE&lowbar;NL

    Hint:ORDERED和USE_NL ORDERED好理解,就是表示根据 from 后面表的顺序join,从左到右,左边的表做驱动表 use_nl(t1,t2):表示对表t1.t2关联时采用嵌套循环 ...

  8. NESTED LOOPS &amp&semi; HASH JOIN &amp&semi; SORT MERGE JOIN

    表连接方式及使用场合 NESTED LOOP 对于被连接的数据子集较小的情况,nested loop连接是个较好的选择.nested loop就是扫描一个表,每读到一条记录,就根据索引去另一个表里面查 ...

  9. Sql优化(一) Merge Join vs&period; Hash Join vs&period; Nested Loop

    原创文章,首发自本人个人博客站点,转载请务必注明出自http://www.jasongj.com Nested Loop,Hash Join,Merge Join介绍 Nested Loop: 对于被 ...

随机推荐

  1. 能源项目xml文件 -- springMVC-servlet&period;xml -- context&colon;component-scan

    <context:component-scan base-package="com.xindatai.ibs" use-default-filters="false ...

  2. CentOS磁盘用完的解决办法&comma;以及Tomcat的server&period;xml里无引用&comma;但是项目仍启动的问题

    这是我2018年的第一篇博客...人真是懒了啊...最近在写微信小程序,觉得小程序做的也... 好了不吐槽了,言归正传 前言: 由于我之前不是买了个三年的香港服务器么 , 之前广州2的服务器我就没有续 ...

  3. unity3d-游戏实战突出重围,第三天 绘制数字

    实现效果: 准备资源 using UnityEngine; using System.Collections; public class hznum : MonoBehaviour { //存储图片资 ...

  4. 小程序WXSS布局

    1. 尽量采用flex 布局,指定flex-direction是row( 从左到右)还是column (从上到下) 特别要记得写 flex-wrap: wrap; 不然超出屏幕部分不会换行 displ ...

  5. clearfix原理

    [clearfix原理] .clearfix:after { <----在类名为“clearfix”的元素内最后面加入内容: content: "."; <----内容 ...

  6. RelativeLayout 相对布局

    根据父容器来定位: 想位于哪,哪个属性就设置为true 左对齐:android:layout_alighParentLeft 右对齐:android:layout_alighParentRight 顶 ...

  7. 变不可能为可能 - &period;NET Windows Form 改变窗体类名(Class Name)有多难?续篇

    发布<.NET Windows Form 改变窗体类名(Class Name)有多难?>转眼大半年过去了,要不是在前几天有园友对这篇文章进行评论,基本上已经很少关注它了,毕竟那只是一个解惑 ...

  8. &lbrack;Noi2014&rsqb;购票 斜率优化DP&plus;可持久化凸包

    貌似网上大部分题解都是CDQ分治+点分治然后再斜率优化DP,我貌似并没有用这个方法. 这一题跟这题有点像,只不过多了一个l的限制 如果说直接跑斜率优化DP,存储整个序列的话,显然是不行的,如图所示(图 ...

  9. Nginx压力测试工具之WebBench

    Nginx压力测试工具之WebBench   在Apache中有自带的ab命令可以测试服务的压力,而nginx没有自带的命令,必须要采用第三方软件来测试,今天就简单介绍一下webbench对nginx ...

  10. Jekyll 使用 Rouge 主题

    今日发现我的 Github Pages 中的代码并没有高亮,看了一下代码发现,原来的没有设置 css 样式的原因,我使用的代码高亮器是 rouge highlighter: rouge Rouge 是 ...