Oracle中常见的Hint(一)
Oracle中的Hint可以用来调整SQL的执行计划,提高SQL执行效率。下面分类介绍Oracle数据库中常见的Hint。这里描述的是Oracle11gR2中的常见Hint,Oracle数据库中各个版本中的Hint都不尽相同,所以这里讲述的的Hint可能并不适用于Oracle早期的版本。
一、与优化器模式相关的Hint
1、ALL_ROWS
ALL_ROWS是针对整个目标SQL的Hint,它的含义是让优化器启用CBO,而且在得到目标SQL的执行计划时会选择那些吞吐量最佳的执行路径。这里的“吞吐量最佳”是指资源消耗量(即对I/O、CPU等硬件资源的消耗量)最小,也就是说在ALL_ROWS Hint生效的情况下,优化器会启用CBO而且会依据各个执行路径的资源消耗量来计算它们各自的成本。
ALL_ROWS Hint的格式如下:
/*+ ALL_ROWS */
使用范例:
1
2
3
|
select /*+ all_rows */ empno,ename,sal,job from emp where empno=7396; |
从Oracle10g开始,ALL_ROWS就是默认的优化器模式,启用的就是CBO。
1
2
3
4
5
|
scott@TEST>show parameter optimizer_mode NAME TYPE ------------------------------------ --------------------------------- ------------------------------ optimizer_mode |
如果目标SQL中除了ALL_ROWS之外还使用了其他与执行路径、表连接相关的Hint,优化器会优先考虑ALL_ROWS。
2、FIRST_ROWS(n)
FIRST_ROWS(n)是针对整个目标SQL的Hint,它的含义是让优化器启用CBO模式,而且在得到目标SQL的执行计划时会选择那些能以最快的响应时间返回头n条记录的执行路径,也就是说在FIRST_ROWS(n) Hint生效的情况下,优化器会启用CBO,而且会依据返回头n条记录的响应时间来决定目标SQL的执行计划。
FIRST_ROWS(n)格式如下:
/*+ FIRST_ROWS(n) */
使用范例
1
2
3
|
select /*+ first_rows(10) */ empno,ename,sal,job from emp where deptno=30; |
上述SQL中使用了/*+ first_rows(10) */,其含义是告诉优化器我们想以最短的响应时间返回满足条件"deptno=30"的前10条记录。
注意,FIRST_ROWS(n) Hint和优化器模式FIRST_ROWS_n不是一一对应的。优化器模式FIRST_ROWS_n中的n只能是1、10、100、1000。但FIRST_ROWS(n) Hint中的n还可以是其他值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
scott@TEST> alter session set optimizer_mode=first_rows_9; ERROR: ORA-00096: invalid value FIRST_ROWS_9 for parameter optimizer_mode, must be from among first_rows_1000, first_rows_100, first_rows_10, first_rows_1, first_rows, all_rows, choose, rule scott@TEST> set autotrace traceonly scott@TEST> select /*+ first_rows(9) */ empno from emp; 14 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 179099197 --------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | INDEX FULL SCAN | PK_EMP | --------------------------------------------------------------------------- |
如果在UPDATE、DELETE或者含如下内容的查询语句中使用了FIRST_ROWS(n) Hint,则该Hint会被忽略:
集合运算(如UNION,INTERSACT,MINUS,UNION ALL等)
GROUP BY
FOR UPDATE
聚合函数(比如SUM等)
DISTINCT
ORDER BY(对应的排序列上没有索引)
这里优化器会忽略FIRST_ROWS(n) Hint是因为对于上述类型的SQL而言,Oracle必须访问所有的行记录后才能返回满足条件的头n行记录,即在上述情况下,使用该Hint是没有意义的。
3、RULE
RULE是针对整个目标SQL的Hint,它表示对目标SQL启用RBO。
格式如下:
/*+ RULE */
使用范例:
1
2
3
|
select /*+ rule */ empno,ename,sal,job from emp where deptno=30; |
RULE不能与除DRIVING_SITE以外的Hint联用,当RULE与除DRIVING_SITE以外的Hint联用时,其他Hint可能会失效;当RULE与DRIVING_SITE联用时,它自身可能会失效,所以RULE Hint最好是单独使用。
一般情况下,并不推荐使用RULE Hint。一来是因为Oracle早就不支持RBO了,二来启用RBO后优化器在执行目标SQL时可选择的执行路径将大大减少,很多执行路径RBO根本就不支持(比如哈希连接),就也就意味着启用RBO后目标SQL跑出正确执行计划的概率将大大降低。
因为很多执行路径RBO根本就不支持,所以即使在目标SQL中使用了RULE Hint,如果出现了如下这些情况(包括但不限于),RULE Hint依然会被Oracle忽略。
目标SQL除RULE之外还联合使用了其他Hint(如DRIVING_SITE)。
目标SQL使用了并行执行
目标SQL所涉及的对象有IOT
目标SQL所涉及的对象有分区表
......
二、与表访问相关的Hint
1、FULL
FULL是针对单个目标表的Hint,它的含义是让优化器对目标表执行全表扫描。
格式如下:
/*+ FULL(目标表) */
使用范例:
1
2
3
|
select /*+ full (emp) */ empno,ename,sal,job from emp where deptno=30; |
上述SQL中Hint的含义是让优化器对目标表EMP执行全表扫描操作,而不考虑走表EMP上的任何索引(即使列EMPNO上有主键索引)。
2、ROIWD
ROIWD是针对单个目标表的Hint,它的含义是让优化器对目标表执行RWOID扫描。只有目标SQL中使用了含ROWID的where条件时ROWID Hint才有意义。
格式如下:
/*+ ROWID(目标表) */
使用范例:
1
2
3
|
select /*+ rowid(emp) */ empno,ename,sal,job from emp where rowid= 'AAAR3xAAEAAAACXAAA' ; |
Oracle 11gR2中即使使用了ROWID Hint,Oracle还是会将读到的块缓存在Buffer Cache中。
三、与索引访问相关的Hint
1、INDEX
INDEX是针对单个目标表的Hint,它的含义是让优化器对目标表的的目标索引执行索引扫描操作。
INDEX Hint中的目标索引几乎可以是Oracle数据库中所有类型的索引(包括B树索引、位图索引、函数索引等)。
INDEX Hint的模式有四种:
格式1 /*+ INDEX(目标表 目标索引) */
格式2 /*+ INDEX(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式3 /*+ INDEX(目标表 (目标索引1的索引列名) (目标索引2的索引列名) …… (目标索引n的索引列名)) */
格式4 /*+ INDEX(目标表) */
格式1表示仅指定了目标表上的一个目标索引,此时优化器只会考虑对这个目标索引执行索引扫描操作,而不会去考虑全表扫描或者对该目标表上的其他索引执行索引扫描操作。
格式2表示指定了目标表上的n个目标索引,此时优化器只会考虑对这n个目标索引执行索引扫描操作,而不会去考虑全表扫描或者对该目标表上的其他索引执行索引扫描操作。注意,优化器在考虑这n个目标索引时,可能是分别计算出单独扫描各个目标索引的成本后,再选择其中成本值最低的索引;也可能是先分别扫描目标索引中的两个或多个索引,然后再对扫描结果执行合并操作。当然,后面这种可能性的前提条件是优化器计算出来这样做的成本值是最低的。
格式三也是表是指定了目标表上的n个目标索引,只不过此时是用指定目标索引的索引列名来代替对应的目标索引名。如果目标索引是复合索引,则在用于指定该索引列名的括号内也可以指定该目标索引的多个索引列,各个索引列之间用空格分隔就可以了。
格式的表示指定了目标表上所有已存在的索引,此时优化器只会考虑对该目标表上所有已存在的索引执行索引扫描操作,而不会去考虑全表扫描操作。注意,这里优化器在考虑该目标表上所有已存在的索引时,可能是分别计算出单独扫描这些索引的成本后再选择其中成本值最低的索引;也可能是先分别扫描这些索引中的两个或多个索引,然后再对扫描结果执行合并操作。当然,后面这种可能性的前提条件是优化器计算出来这样做的成本值是最低的。
使用范例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
select /*+ index (emp pk_emp) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ index (emp pk_emp idx_emp_mgr idx_emp_dept) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ index (emp (empno) (mgr) (deptno)) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ index */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; |
2、NO_INDEX
NO_INDEX是针对单个目标表的Hint,它是INDEX的反义Hint,其含义是让优化器不对目标表上的目标索引执行扫描操作。
INDEX Hint中的目标索引也几乎可以是Oracle数据库中所有类型的索引(包括B树索引、位图索引、函数索引等)。
格式有如下三种:
格式1 /*+ NO_INDEX(目标表 目标索引) */
格式2 /*+ NO_INDEX(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式3 /*+ NO_INDEX(目标表) */
格式1表示仅指定了目标表上的一个目标索引,此时优化器只是不会考虑对这个目标索引执行索引扫描操作,但还是会考虑全表扫描或者对该目标表上的其他索引执行索引扫描操作。
格式2表示指定了目标表上的n个目标索引,此时优化器只是不会考虑对这n个目标索引执行索引扫描操作,但还是会考虑全表扫描或者对该目标表上的其他索引执行索引扫描操作。
格式3表示指定了目标表上的所有已存在的索引,即此时优化器不会考虑对该目标表上所有已存在的索引执行索引扫描操作,这相当于对目标表指定了全表扫描。
使用范例:
1
2
3
4
5
6
7
8
9
10
11
|
select /*+ no_index(emp pk_emp) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ no_index(emp pk_emp idx_emp_mgr idx_emp_dept) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ no_index */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; |
3、INDEX_DESC
INDEX_DESC是针对单个目标表的Hint,它的含义是让优化器对目标表上的目标索引执行索引降序扫描操作。如果目标索引是升序的,则INDEX_DESC Hint会使Oracle以降序的方式扫描该索引;如果目标索引是降序的,则INDEX_DESC Hint会使Oracle以升序的方式扫描该索引。
格式有三种:
格式1 /*+ INDEX_DESC(目标表 目标索引) */
格式2 /*+ INDEX_DESC(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式3 /*+ INDEX_DESC(目标表) */
上述3种格式的含义和INDEX中对应格式的含义相同。
使用范例:
1
2
3
4
5
6
7
8
9
10
11
|
select /*+ index_desc(emp pk_emp) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ index_desc(emp pk_emp idx_emp_mgr idx_emp_dept) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ index_desc */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; |
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
scott@TEST> select /*+ index_desc(emp,pk_emp) */ empno from emp; EMPNO ---------- 7934 7902 7900 7876 7844 7839 7788 7782 7698 7654 7566 7521 7499 7369 14 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1838043032 ------------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | 1 | INDEX FULL SCAN DESCENDING| PK_EMP | ------------------------------------------------------------------------------------- ...... |
4、INDEX_COMBINE
INDEX_COMBINE是针对单个目标表的Hint,它的含义是让优化器对目标表上的多个目标索引执行位图布尔运算。Oracle数据库里有一个映射函数(Mapping Function),它可以实例B*Tree索引中的ROWID和对应位图索引中的位图之间的互相转换,所以INDEX_COMBINE Hint并不局限于位图索引,它的作用对象也可以是B*Tree索引。
格式有如下两种
格式1 /*+ INDEX_COMBINE(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式2 /*+ INDEX_COMBINE(目标表) */
格式1表示指定了目标表上的n个目标索引,此时优化器会考虑对这n个目标索引中的两个或多个执行位图布尔运算。
格式2表示指定了目标表上所有已存在的索引,此时优化器会考虑对该表上已存在的所有索引中的两个或多个执行位图布尔运算。
使用范例:
1
2
3
4
5
6
7
8
9
10
11
|
select /*+ index_combine(emp pk_emp idx_emp_mgr) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 ; select /*+ index_combine(emp pk_emp idx_emp_mgr idx_emp_deptno) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; select /*+ index_combine(emp) */ empno,ename,sal,job from emp where empno=7369 and mgr=7902 and deptno=20; |
下面看一个实例,在表EMP上创建两个索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
scott@TEST> create index idx_emp_mgr on emp(mgr); Index created. scott@TEST> create index idx_emp_dept on emp(deptno); Index created. scott@TEST> select /*+ index_combine(emp pk_emp idx_emp_mgr idx_emp_deptno) */ empno,ename,sal,job 2 from emp 3 where empno=7369 and mgr=7902 and deptno=20; EMPNO ENAME ---------- ------------------------------ ---------- --------------------------- 7369 SMITH Execution Plan ---------------------------------------------------------- Plan hash value: 1816402415 ------------------------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | 1 | TABLE ACCESS BY INDEX ROWID | 2 | BITMAP CONVERSION TO ROWIDS | 3 | BITMAP AND | | 4 | BITMAP CONVERSION FROM ROWIDS| |* 5 | INDEX RANGE SCAN | 6 | BITMAP CONVERSION FROM ROWIDS| |* 7 | INDEX RANGE SCAN | 8 | BITMAP CONVERSION FROM ROWIDS| |* 9 | INDEX RANGE SCAN ------------------------------------------------------------------------------------------------- ...... |
从上面的执行计划中可以看到关键字“BITMAP CONVERSION FROM ROWIDS”、“BITMAP AND”和“BITMAP CONVERSION TO ROWIDS”,这说明Oracle先分别对上述三个单键值的B*Tree索引IDX_EMP_MGR、IDX_EMP_DEPT和PK_EMP用映射函数将其中的ROWID转换成了位图,然后对转换后的位图执行了BITMAP AND(位图按位与)布尔运算,最后将布尔运算的结果再次用映射函数转换成了ROWID并回表得到最终的执行结果。能走出这样的执行计划显然是因为INDEX_COMBINE
Hint生效了。
用映射函数将ROWID转换成了位图,然后再执行布尔运算,最后将布尔运算的结果再次用映射函数转换成了ROWID并回表得到最终的执行结果,这个过程在实际生产环境中的执行效率可能是有问题的,可以使用隐含参数_B_TREE_BITMAP_PLANS禁掉该过程中的ROWID到位图的转换:
alter session set "_b_tree_bitmap_plans"=false;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
scott@TEST> alter session set "_b_tree_bitmap_plans" = false ; Session altered. scott@TEST> select /*+ index_combine(emp pk_emp idx_emp_mgr idx_emp_deptno) */ empno,ename,sal,job 2 from emp 3 where empno=7369 and mgr=7902 and deptno=20; EMPNO ENAME ---------- ------------------------------ ---------- --------------------------- 7369 SMITH Execution Plan ---------------------------------------------------------- Plan hash value: 2949544139 -------------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT |* 1 | TABLE ACCESS BY INDEX ROWID| EMP | |* 2 | INDEX UNIQUE SCAN -------------------------------------------------------------------------------------- ...... |
从上面的执行计划中可以看出没有出现BITMAP相关的关键字,即INDEX_COMBINE Hint被Oracle忽略了。
5、INDEX_FFS
INDEX_FFS是针对单个目标表的Hint,它的含义是让优化器对目标表上的目标索引执行索引快速全扫描操作。注意,索引快速全扫描能成立的前提条件是SELECT语句中所有的查询列都存在于目标索引中,即通过扫描目标索引就可以得到所有的查询列而不用回表。
格式有如下三种:
格式1 /*+ INDEX_FFS(目标表 目标索引) */
格式2 /*+ INDEX_FFS(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式3 /*+ INDEX_FFS(目标表) */
上述3种格式的含义和INDEX中对应格式的含义相同。
使用范例:
1
2
3
4
5
6
7
8
9
10
11
|
select /*+ index_ffs(emp pk_emp) */ empno from emp; select /*+ index_ffs(emp idx_emp_1 idx_emp_2) */ empno from emp where mgr=7902 and deptno=20; --create index idx_emp_1 on emp(mgr,deptno,1); --create index idx_emp_2 on emp(mgr,deptno,2); select /*+ index_ffs(emp) */ empno from emp; |
看下面的实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
scott@TEST> select empno from emp; 14 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 179099197 --------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | INDEX FULL SCAN | PK_EMP | 10 | 40 | --------------------------------------------------------------------------- ...... scott@TEST> select /*+ index_ffs(emp) */empno from emp; 14 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 366039554 ------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | INDEX FAST FULL SCAN| PK_EMP | 10 | 40 | 2 ------------------------------------------------------------------------------- ...... |
6、INDEX_JOIN
INDEX_JOIN是针对单个目标表的Hint,它的含义是让优化器对目标表上的多个目标索引执行INDEX JOIN操作。INDEX JOIN能成立的前提条件是SELECT语句中所有的查询列都存在于目标表上的多个目标索引中,即通过扫描这些索引就可以得到所有的查询列而不用回表。
格式如下:
格式1 /*+ INDEX_JOIN(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式2 /*+ INDEX_JOIN */
上述两种格式的含义与INDEX_COMBINE Hint中对应格式的含义相同。
使用范例:
1
2
3
4
5
6
7
|
select /*+ index_join(emp pk_emp idx_emp_mgr) */ empno,mgr from emp where empno>7369 and mgr<7902; select /*+ index_join(emp) */ empno,mgr from emp where empno>7369 and mgr<7902; |
来看下面的实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
scott@TEST> select empno,mgr 2 from emp 3 where empno>7369 and mgr<7902; 12 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 2059184959 ------------------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT |* 1 | TABLE ACCESS BY INDEX ROWID| EMP |* 2 | INDEX RANGE SCAN ------------------------------------------------------------------------------------------- ...... scott@TEST> select /*+ index_join(emp) */ empno,mgr 2 from emp 3 where empno>7369 and mgr<7902; 12 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 3030719951 --------------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | |* 1 | VIEW | index $_join$_001 | 10 | 80 | 3 (34)| 00:00:01 | |* 2 | HASH JOIN | |* 3 | INDEX RANGE SCAN| IDX_EMP_MGR | 10 | 80 | 2 (50)| 00:00:01 | |* 4 | INDEX RANGE SCAN| PK_EMP --------------------------------------------------------------------------------------- ...... |
7、AND_EQUAL
AND_EQUAL是针对单个目标表的Hint,它的含义是让优化器对目标表上的多个目标索引执行INDEX MERGE操作。INDEX MERGE能成立的前提条件是目标SQL的where条件里出现了多个针对不同单列的等值条件,并且这些列上都有单键值的索引。另外,在Oracle数据库里,能够做INDEX MERGE的索引数量的最大值是5。
格式如下:
/*+ AND_EQUAL(目标表 目标索引1 目标索引2 …… 目标索引n)*/
使用范例:
1
2
3
|
select /*+ and_equal(emp idx_emp_mgr idx_emp_dept) */ empno,mgr from emp where deptno=20 and mgr=7902; |
看下面的实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
scott@TEST> select empno,mgr 2 from emp 3 where deptno=20 and mgr=7902; Execution Plan ---------------------------------------------------------- Plan hash value: 2059184959 ------------------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT |* 1 | TABLE ACCESS BY INDEX ROWID| EMP |* 2 | INDEX RANGE SCAN ------------------------------------------------------------------------------------------- ...... scott@TEST> select /*+ and_equal(emp idx_emp_mgr idx_emp_dept) */ empno,mgr 2 from emp 3 where deptno=20 and mgr=7902; Execution Plan ---------------------------------------------------------- Plan hash value: 3295440569 -------------------------------------------------------------------------------------------- | Id | Operation Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT |* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 2 | AND -EQUAL |* 3 | INDEX RANGE SCAN |* 4 | INDEX RANGE SCAN -------------------------------------------------------------------------------------------- ...... |
四、与表连接顺序相关的Hint
1、ORDERED
ORDERED是针对多个目标表的Hint,它的含义是让优化器对多个目标表执行表连接操作时,执照它们在目标SQL的where条件中出现的顺序从左到右依次进行连接。
格式如下:
/*+ ORDERED */
使用范例:
1
2
3
4
5
6
|
select /*+ ordered */ e.ename,j.job,e.sal,d.deptno from emp e,jobs j,dept d where e.empno=j.empno and e.deptno=d.deptno and d.loc= 'CHICAGO' order by e.ename; |
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
scott@TEST> select e.ename,j.job,e.sal,d.deptno 2 from emp e,jobs j,dept d 3 where e.empno=j.empno 4 and e.deptno=d.deptno 5 and d.loc= 'CHICAGO' 6 order by e.ename; 6 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 4113290228 ----------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 235 | 9 (23)| 00:00:01 | | 1 | SORT ORDER BY | | 5 | 235 | 9 (23)| 00:00:01 | |* 2 | HASH JOIN | | 5 | 235 | 8 (13)| 00:00:01 | | 3 | NESTED LOOPS | | | | | | | 4 | NESTED LOOPS | | 5 | 140 | 4 (0)| 00:00:01 | |* 5 | TABLE ACCESS FULL | DEPT | 1 | 11 | 3 (0)| 00:00:01 | |* 6 | INDEX RANGE SCAN | IDX_EMP_DEPT | 5 | | 0 (0)| 00:00:01 | | 7 | TABLE ACCESS BY INDEX ROWID| EMP | 5 | 85 | 1 (0)| 00:00:01 | | 8 | TABLE ACCESS FULL | JOBS | 14 | 266 | 3 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------- ...... scott@TEST> select /*+ ordered */ e.ename,j.job,e.sal,d.deptno 2 from emp e,jobs j,dept d 3 where e.empno=j.empno 4 and e.deptno=d.deptno 5 and d.loc= 'CHICAGO' 6 order by e.ename; 6 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 3031293267 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 235 | 11 (28)| 00:00:01 | | 1 | SORT ORDER BY | | 5 | 235 | 11 (28)| 00:00:01 | |* 2 | HASH JOIN | | 5 | 235 | 10 (20)| 00:00:01 | | 3 | MERGE JOIN | | 14 | 504 | 6 (17)| 00:00:01 | | 4 | TABLE ACCESS BY INDEX ROWID| EMP | 14 | 238 | 2 (0)| 00:00:01 | | 5 | INDEX FULL SCAN | PK_EMP | 14 | | 1 (0)| 00:00:01 | |* 6 | SORT JOIN | | 14 | 266 | 4 (25)| 00:00:01 | | 7 | TABLE ACCESS FULL | JOBS | 14 | 266 | 3 (0)| 00:00:01 | |* 8 | TABLE ACCESS FULL | DEPT | 1 | 11 | 3 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- ...... scott@TEST> select /*+ ordered */ e.ename,j.job,e.sal,d.deptno 2 from emp e,dept d,jobs j 3 where e.empno=j.empno 4 and e.deptno=d.deptno 5 and d.loc= 'CHICAGO' 6 order by e.ename; 6 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1175157407 ----------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 235 | 11 (28)| 00:00:01 | | 1 | SORT ORDER BY | | 5 | 235 | 11 (28)| 00:00:01 | |* 2 | HASH JOIN | | 5 | 235 | 10 (20)| 00:00:01 | | 3 | MERGE JOIN | | 5 | 140 | 6 (17)| 00:00:01 | | 4 | TABLE ACCESS BY INDEX ROWID| EMP | 14 | 238 | 2 (0)| 00:00:01 | | 5 | INDEX FULL SCAN | IDX_EMP_DEPT | 14 | | 1 (0)| 00:00:01 | |* 6 | SORT JOIN | | 1 | 11 | 4 (25)| 00:00:01 | |* 7 | TABLE ACCESS FULL | DEPT | 1 | 11 | 3 (0)| 00:00:01 | | 8 | TABLE ACCESS FULL | JOBS | 14 | 266 | 3 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------- ...... |
从上面的执行计划可以看出不使用ordered Hint时表扫描的顺序是DEPT->EMP->JOBS,但是使用ordered Hint后,表扫描的顺序变为了EMP->JOBS->DEPT与目标SQL中的顺序一致了,在修改了目标SQL文本之后表的扫描顺序也相应地变为了EMP->DEPT->JOBS。
2、LEADING
LEADING是针对多个目标表的Hint,它的含义是让优化器将我们指定的多个表的连接结果作为目标SQL表连接过程中的驱动结果集,并且将LEADING Hint中从左至右出现的第一个目标表作为整个表连接过程中的首个驱动表。
LEADING比ORDERED要温和一些,因为它只是指定了首个驱动表和驱动结果集,没有像ORDERED那样完全指定了表连接的顺序,也就是说LEADING给了优化器更大的调整余地。
当LEADING Hint中指定的表并不能作为目标SQL的连接过程中的驱动表或者驱动结果集时,Oracle会忽略该Hint。
格式如下:
/*+ LEADING(目标表1 目标表2 …… 目标表n) */
使用范例:
1
2
3
4
5
6
7
|
select /*+ leading(t e) */ e.ename,j.job,e.sal,d.deptno from emp e,jobs j,dept d,emp_temp t where e.empno=j.empno and e.deptno=d.deptno and d.loc= 'CHICAGO' and e.ename=t.ename order by e.ename; |
实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
--不使用Hint scott@TEST> select e.ename,j.job,e.sal,d.deptno 2 from emp e,jobs j,dept d,emp_temp t 3 where e.empno=j.empno 4 and e.deptno=d.deptno 5 and d.loc= 'CHICAGO' 6 and e.ename=t.ename 7 order by e.ename; 6 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 558051962 ------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 5 | 270 | 12 (17)| 00:00:01 | | 1 | SORT ORDER BY | | 5 | 270 | 12 (17)| 00:00:01 | |* 2 | HASH JOIN | | 5 | 270 | 11 (10)| 00:00:01 | |* 3 | HASH JOIN | | 5 | 235 | 8 (13)| 00:00:01 | | 4 | NESTED LOOPS | | | | | | | 5 | NESTED LOOPS | | 5 | 140 | 4 (0)| 00:00:01 | |* 6 | TABLE ACCESS FULL | DEPT | 1 | 11 | 3 (0)| 00:00:01 | |* 7 | INDEX RANGE SCAN | IDX_EMP_DEPT | 5 | | 0 (0)| 00:00:01 | | 8 | TABLE ACCESS BY INDEX ROWID| EMP | 5 | 85 | 1 (0)| 00:00:01 | | 9 | TABLE ACCESS FULL | JOBS | 14 | 266 | 3 (0)| 00:00:01 | | 10 | TABLE ACCESS FULL | EMP_TEMP | 14 | 98 | 3 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------ ...... --使用LEADING Hint scott@TEST> select /*+ leading(t e) */ e.ename,j.job,e.sal,d.deptno 2 from emp e,jobs j,dept d,emp_temp t 3 where e.empno=j.empno 4 and e.deptno=d.deptno 5 and d.loc= 'CHICAGO' 6 and e.ename=t.ename 7 order by e.ename; 6 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 937897748 ---------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 270 | 15 (20)| 00:00:01 | | 1 | SORT ORDER BY | | 5 | 270 | 15 (20)| 00:00:01 | |* 2 | HASH JOIN | | 5 | 270 | 14 (15)| 00:00:01 | |* 3 | HASH JOIN | | 5 | 175 | 10 (10)| 00:00:01 | |* 4 | HASH JOIN | | 14 | 336 | 7 (15)| 00:00:01 | | 5 | TABLE ACCESS FULL | EMP_TEMP | 14 | 98 | 3 (0)| 00:00:01 | | 6 | TABLE ACCESS FULL | EMP | 14 | 238 | 3 (0)| 00:00:01 | |* 7 | TABLE ACCESS FULL | DEPT | 1 | 11 | 3 (0)| 00:00:01 | | 8 | TABLE ACCESS FULL | JOBS | 14 | 266 | 3 (0)| 00:00:01 | ---------------------------------------------------------------------------------- ...... --使用Ordered Hint scott@TEST> select /*+ ordered */ e.ename,j.job,e.sal,d.deptno 2 from emp e,jobs j,dept d,emp_temp t 3 where e.empno=j.empno 4 and e.deptno=d.deptno 5 and d.loc= 'CHICAGO' 6 and e.ename=t.ename 7 order by e.ename; 6 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 2459794491 -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 270 | 14 (22)| 00:00:01 | | 1 | SORT ORDER BY | | 5 | 270 | 14 (22)| 00:00:01 | |* 2 | HASH JOIN | | 5 | 270 | 13 (16)| 00:00:01 | |* 3 | HASH JOIN | | 5 | 235 | 10 (20)| 00:00:01 | | 4 | MERGE JOIN | | 14 | 504 | 6 (17)| 00:00:01 | | 5 | TABLE ACCESS BY INDEX ROWID| EMP | 14 | 238 | 2 (0)| 00:00:01 | | 6 | INDEX FULL SCAN | PK_EMP | 14 | | 1 (0)| 00:00:01 | |* 7 | SORT JOIN | | 14 | 266 | 4 (25)| 00:00:01 | | 8 | TABLE ACCESS FULL | JOBS | 14 | 266 | 3 (0)| 00:00:01 | |* 9 | TABLE ACCESS FULL | DEPT | 1 | 11 | 3 (0)| 00:00:01 | | 10 | TABLE ACCESS FULL | EMP_TEMP | 14 | 98 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------------------------- ...... |
从上面的执行计划可以看出不使用Hint时表扫描顺序是DEPT->EMP->JOBS->EMP_TEMP;使用LEADING Hint时表扫描顺序是EMP_TEMP->EMP->DEPT->JOBS,EMP_TEMP做首个驱动表和表EMP的连接结果做为驱动结果集,与Hint要求一致。;使用Ordered Hint时表扫描顺序是EMP->JOBS->DEPT->EMP_TEMP,与SQL中顺序一致。
原文地址:https://blog.csdn.net/tmchongye/article/details/64389420
Oracle中常见的Hint(一)的更多相关文章
- ORACLE中常见的几种锁
ORACLE中常见的几种锁: 0:none 1:null 空 2:Row-S 行共享(RS):共享表锁,sub share 3:Row-X 行独占(RX):用于行的修改,sub exclusive 4 ...
- Oracle中常见的33个等待事件小结
在Oracle 10g中的等待事件有872个,11g中等待事件1116个. 我们可以通过v$event_name 视图来查看等待事件的相关信息 一. 等待事件的相关知识 1.1 等待事件主要可 ...
- Oracle性能优化之oracle中常见的执行计划及其简单解释
一.访问表执行计划 1.table access full:全表扫描.它会访问表中的每一条记录(读取高水位线以内的每一个数据块). 2.table access by user rowid:输入源ro ...
- ORACLE中常见SET指令
1 SET TIMING ON 说明:显示SQL语句的运行时间.默认值为OFF. 在SQLPLUS中使用,时间精确到0.01秒.也就是10毫秒. 在PL/SQL DEVELOPER 中 ...
- Oracle中常见表与各类结构的查询
----------------------------------------------------------------------用户--查询:当前用户的缺省表空间select userna ...
- oracle中常见的对表、表空间和视图的操作
创建表:create table t1(key1 type default 0,key2 type not null) 删除表:drop table t1; 删除表数据:truncate table ...
- oracle中常见的查询操作
普通查询:select * from t; 去除重复值:select distinct f1,f2 from t; between用法:select * from t where f1 not/bet ...
- SQL优化过程中常见Oracle HINT
在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...
- 2、Java应用中常见的JDBC连接字符串(SQLite、MySQL、Oracle、Sybase、SQLServer、DB2)
2.Java应用中常见的JDBC连接字符串 Java应用中连接数据库是不可或缺的,于是便整理一些可能用到的JDBC的jar包及其相匹配的URL,以备日后查阅. 1)SQLite Class.forNa ...
随机推荐
- [fW]中断处理函数数组interrupt[]初始化
中断处理函数数组interrupt[]初始化 2011-05-13 15:51:40 分类: LINUX 在系统初始化期间,trap_init()函数将对中断描述符表IDT进行第二次初始化(第一次只是 ...
- vue证明题X,vue设置集
1.开发中的控制台tab格式警告隐藏 出现情况如图: 解决方案:找到此代码,注释掉 2.控制台error报告 出现情况如图 解决方案:找到此代码,替换,对浏览器中的警告进行隐藏 遇到就更
- JavaScript寻找最长的单词算法
返回提供的句子中最长的单词的长度. 返回值应该是一个数字. 第一步,使用String.prototype.split()方法将字符串转换成数组 function findLongestWord(str ...
- showmount - 显示关于 NFS 服务器文件系统挂载的信息
总览 /usr/sbin/showmount [ -adehv ] [ --all ] [ --directories ] [ --exports ] [ --help ] [ --version ] ...
- 深度学习之Tensorflow 工程化项目实战 配套资源
https://www.aianaconda.com/index/CodeProject
- 力扣—gray code (格雷编码) python实现
题目描述: 中文: 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头. 英文: Th ...
- 阿里云安装Cloudera Manager(草稿)
选择三台同一局域网的阿里云服务器 最初使用阿里云.京东云.百度云的三台不同的服务器,遇到一些问题,没有解决,公网速度也没有保障,还是选择同一局域网的服务器吧 CM有三种不同的安装方式: 通过 Clou ...
- linux文件查找工具——locate,find
一文件查找介绍 文件的查找就是在文件系统上查找符合条件的文件. 文件查找的方式:locate, find非实时查找也就是基于数据库查找的locate,效率特别高. 实时查找:find 二locate ...
- noi2019感想
不知道怎么想的,我现在已经没有心情写一篇完整的游记了. 发挥的是真的太差,Day1该切的T2没有切掉,想的时候漏了一个性质,便由100->45. Day1的时间全花在了T3上,结果想歪了,最后只 ...
- hdu 3572 Task Schedule (Dinic模板)
Problem Description Our geometry princess XMM has stoped her study in computational geometry to conc ...