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 ...
随机推荐
- [Leetcode] 176.第二高薪水
题目: 编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) . +----+--------+ | Id | Salary | +----+--------+ | 1 | ...
- Scrapy框架: 通用爬虫之CSVFeedSpider
步骤01: 创建项目 scrapy startproject csvfeedspider 步骤02: 使用csvfeed模版 scrapy genspider -t csvfeed csvdata g ...
- 配置静态IP时候route没有设置的GATEWAY问题
今天在想把虚拟机里RHEL6.5设置成静态IP来着 在 /etc/sysconfig/betwork-scripts/ifcfg-eth0 文件中将"GATEWAY"拼写成了&qu ...
- NOIP后一波总结
我的山寨较为可靠分数为305(洛谷是真的水~显然不能用啊,果断换了一组合适的数据) 据大神们估计,得奖的分数在280, 我肯定是没有啥希望了.(我旁边的lxy同学从初二开始,每次以超分数线至少60分的 ...
- [Java 教程 02] 开发环境搭建
在上一篇文章对Java做了一个简单介绍之后,我想大家都已经对她有一个初步的认识了吧!那踏入正式学习使用Java之前,我们有一步是不得不做的,它是什么呢?没有错,就是我们本篇文章的标题所说,搭建Java ...
- REST接口设计
REST接口设计 为什么要有REST 在传统上,软件和网络是两个不同的领域,很少有交集:软件开发主要针对单机环境,网络则主要研究系统之间的通信.互联网的兴起,使得这两个领域开始融合,现在我们必须考虑, ...
- RxJava的学习与实现
RxJava 要在Android中使用RxJava2, 先添加Gradle配置: compile 'io.reactivex.rxjava2:rxjava:2.0.1' compile 'io.rea ...
- showkey - 检查来自键盘的扫描码和键盘码
览 (SYNOPSIS) showkey [ -[hVskm] | --help | --version | --scancodes | --keycodes | --keymap ] [ -t N ...
- redis单节点安装及cluster的安装
单点安装 wget http://download.redis.io/releases/redis-4.0.2.tar.gz tar zxvf redis-4.0.1.tar.gz -C /usr/l ...
- visual Studio如何使用断点调试程序?
1.在想要添加断点的地方右侧点击,点击成功后会出现红色原点. 2.启动程序,当进行到断点处时,程序会停止,然后可以看到一个黄色的小箭头在断点处 3.快捷键F10:进行下一句代码 4.快捷键F11:进入 ...