Oracle中的Hint能够用来调整SQL的执行计划,提升SQL执行效率。下面分类介绍Oracle数据库中常见的Hint。这里描述的是Oracle11gR2中的常见Hint,Oracle数据库中各个版本中的Hint都不尽相同,因此这里讲述的的Hint可能并不适用于Oracle早期的版本。sql
1、与优化器模式相关的Hint数据库
一、ALL_ROWS缓存
ALL_ROWS是针对整个目标SQL的Hint,它的含义是让优化器启用CBO,并且在获得目标SQL的执行计划时会选择那些吞吐量最佳的执行路径。这里的“吞吐量最佳”是指资源消耗量(即对I/O、CPU等硬件资源的消耗量)最小,也就是说在ALL_ROWS Hint生效的状况下,优化器会启用CBO并且会依据各个执行路径的资源消耗量来计算它们各自的成本。session
ALL_ROWS Hint的格式以下:oracle
/*+ ALL_ROWS */app
使用范例:ide
select /*+ all_rows */ empno,ename,sal,job from emp where empno=7396;
从Oracle10g开始,ALL_ROWS就是默认的优化器模式,启用的就是CBO。函数
scott@TEST>show parameter optimizer_mode NAME TYPE VALUE ------------------------------------ --------------------------------- ------------------------------ optimizer_mode string ALL_ROWS
若是目标SQL中除了ALL_ROWS以外还使用了其余与执行路径、表链接相关的Hint,优化器会优先考虑ALL_ROWS。优化
二、FIRST_ROWS(n)spa
FIRST_ROWS(n)是针对整个目标SQL的Hint,它的含义是让优化器启用CBO模式,并且在获得目标SQL的执行计划时会选择那些能以最快的响应时间返回头n条记录的执行路径,也就是说在FIRST_ROWS(n) Hint生效的状况下,优化器会启用CBO,并且会依据返回头n条记录的响应时间来决定目标SQL的执行计划。
FIRST_ROWS(n)格式以下:
/*+ FIRST_ROWS(n) */
使用范例
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只能是一、十、100、1000。但FIRST_ROWS(n) Hint中的n还能够是其余值。
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 | | 9 | 36 | 1 (0)| 00:00:01 | | 1 | INDEX FULL SCAN | PK_EMP | 9 | 36 | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------
若是在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是没有意义的。
三、RULE
RULE是针对整个目标SQL的Hint,它表示对目标SQL启用RBO。
格式以下:
/*+ RULE */
使用范例:
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所涉及的对象有分区表
......
2、与表访问相关的Hint
一、FULL
FULL是针对单个目标表的Hint,它的含义是让优化器对目标表执行全表扫描。
格式以下:
/*+ FULL(目标表) */
使用范例:
select /*+ full(emp) */ empno,ename,sal,job from emp where deptno=30;
上述SQL中Hint的含义是让优化器对目标表EMP执行全表扫描操做,而不考虑走表EMP上的任何索引(即便列EMPNO上有主键索引)。
二、ROIWD
ROIWD是针对单个目标表的Hint,它的含义是让优化器对目标表执行RWOID扫描。只有目标SQL中使用了含ROWID的where条件时ROWID Hint才有意义。
格式以下:
/*+ ROWID(目标表) */
使用范例:
select /*+ rowid(emp) */ empno,ename,sal,job from emp where rowid='AAAR3xAAEAAAACXAAA';
Oracle 11gR2中即便使用了ROWID Hint,Oracle仍是会将读到的块缓存在Buffer Cache中。
3、与索引访问相关的Hint
一、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个目标索引,只不过此时是用指定目标索引的索引列名来代替对应的目标索引名。若是目标索引是复合索引,则在用于指定该索引列名的括号内也能够指定该目标索引的多个索引列,各个索引列之间用空格分隔就能够了。
格式的表示指定了目标表上全部已存在的索引,此时优化器只会考虑对该目标表上全部已存在的索引执行索引扫描操做,而不会去考虑全表扫描操做。注意,这里优化器在考虑该目标表上全部已存在的索引时,多是分别计算出单独扫描这些索引的成本后再选择其中成本值最低的索引;也多是先分别扫描这些索引中的两个或多个索引,而后再对扫描结果执行合并操做。固然,后面这种可能性的前提条件是优化器计算出来这样作的成本值是最低的。
使用范例:
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;
二、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表示指定了目标表上的全部已存在的索引,即此时优化器不会考虑对该目标表上全部已存在的索引执行索引扫描操做,这至关于对目标表指定了全表扫描。
使用范例:
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;
三、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中对应格式的含义相同。
使用范例:
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;
实例:
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 | | 10 | 40 | 1 (0)| 00:00:01 | | 1 | INDEX FULL SCAN DESCENDING| PK_EMP | 10 | 40 | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------- ......
四、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表示指定了目标表上全部已存在的索引,此时优化器会考虑对该表上已存在的全部索引中的两个或多个执行位图布尔运算。
使用范例:
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上建立两个索引
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 SAL JOB ---------- ------------------------------ ---------- --------------------------- 7369 SMITH 800 CLERK Execution Plan ---------------------------------------------------------- Plan hash value: 1816402415 ------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 29 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 29 | 2 (0)| 00:00:01 | | 2 | BITMAP CONVERSION TO ROWIDS | | | | | | | 3 | BITMAP AND | | | | | | | 4 | BITMAP CONVERSION FROM ROWIDS| | | | | | |* 5 | INDEX RANGE SCAN | PK_EMP | | | 0 (0)| 00:00:01 | | 6 | BITMAP CONVERSION FROM ROWIDS| | | | | | |* 7 | INDEX RANGE SCAN | IDX_EMP_MGR | | | 1 (0)| 00:00:01 | | 8 | BITMAP CONVERSION FROM ROWIDS| | | | | | |* 9 | INDEX RANGE SCAN | IDX_EMP_DEPT | | | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------- ......
从上面的执行计划中能够看到关键字“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;
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 SAL JOB ---------- ------------------------------ ---------- --------------------------- 7369 SMITH 800 CLERK Execution Plan ---------------------------------------------------------- Plan hash value: 2949544139 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 29 | 1 (0)| 00:00:01 | |* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 29 | 1 (0)| 00:00:01 | |* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 | -------------------------------------------------------------------------------------- ......
从上面的执行计划中能够看出没有出现BITMAP相关的关键字,即INDEX_COMBINE Hint被Oracle忽略了。
五、INDEX_FFS
INDEX_FFS是针对单个目标表的Hint,它的含义是让优化器对目标表上的目标索引执行索引快速全扫描操做。注意,索引快速全扫描能成立的前提条件是SELECT语句中全部的查询列都存在于目标索引中,即经过扫描目标索引就能够获得全部的查询列而不用回表。
格式有以下三种:
格式1 /*+ INDEX_FFS(目标表 目标索引) */
格式2 /*+ INDEX_FFS(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式3 /*+ INDEX_FFS(目标表) */
上述3种格式的含义和INDEX中对应格式的含义相同。
使用范例:
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;
看下面的实例:
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 | | 10 | 40 | 1 (0)| 00:00:01 | | 1 | INDEX FULL SCAN | PK_EMP | 10 | 40 | 1 (0)| 00:00:01 | --------------------------------------------------------------------------- ...... 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 | | 10 | 40 | 2 (0)| 00:00:01 | | 1 | INDEX FAST FULL SCAN| PK_EMP | 10 | 40 | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------- ......
六、INDEX_JOIN
INDEX_JOIN是针对单个目标表的Hint,它的含义是让优化器对目标表上的多个目标索引执行INDEX JOIN操做。INDEX JOIN能成立的前提条件是SELECT语句中全部的查询列都存在于目标表上的多个目标索引中,即经过扫描这些索引就能够获得全部的查询列而不用回表。
格式以下:
格式1 /*+ INDEX_JOIN(目标表 目标索引1 目标索引2 …… 目标索引n) */
格式2 /*+ INDEX_JOIN */
上述两种格式的含义与INDEX_COMBINE Hint中对应格式的含义相同。
使用范例:
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;
来看下面的实例:
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 | | 10 | 80 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 10 | 80 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_EMP_MGR | 11 | | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------- ...... 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 | | 10 | 80 | 3 (34)| 00:00:01 | |* 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 | 10 | 80 | 2 (50)| 00:00:01 | --------------------------------------------------------------------------------------- ......
七、AND_EQUAL
AND_EQUAL是针对单个目标表的Hint,它的含义是让优化器对目标表上的多个目标索引执行INDEX MERGE操做。INDEX MERGE能成立的前提条件是目标SQL的where条件里出现了多个针对不一样单列的等值条件,而且这些列上都有单键值的索引。另外,在Oracle数据库里,可以作INDEX MERGE的索引数量的最大值是5。
格式以下:
/*+ AND_EQUAL(目标表 目标索引1 目标索引2 …… 目标索引n)*/
使用范例:
select /*+ and_equal(emp idx_emp_mgr idx_emp_dept) */ empno,mgr from emp where deptno=20 and mgr=7902;
看下面的实例:
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 | 11 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 11 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_EMP_MGR | 2 | | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------- ...... 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 | 11 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 11 | 3 (0)| 00:00:01 | | 2 | AND-EQUAL | | | | | | |* 3 | INDEX RANGE SCAN | IDX_EMP_MGR | 2 | | 1 (0)| 00:00:01 | |* 4 | INDEX RANGE SCAN | IDX_EMP_DEPT | 5 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------------- ......
4、与表链接顺序相关的Hint
一、ORDERED
ORDERED是针对多个目标表的Hint,它的含义是让优化器对多个目标表执行表链接操做时,执照它们在目标SQL的where条件中出现的顺序从左到右依次进行链接。
格式以下:
/*+ ORDERED */
使用范例:
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;
实例:
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。
二、LEADING
LEADING是针对多个目标表的Hint,它的含义是让优化器将咱们指定的多个表的链接结果做为目标SQL表链接过程当中的驱动结果集,而且将LEADING Hint中从左至右出现的第一个目标表做为整个表链接过程当中的首个驱动表。
LEADING比ORDERED要温和一些,由于它只是指定了首个驱动表和驱动结果集,没有像ORDERED那样彻底指定了表链接的顺序,也就是说LEADING给了优化器更大的调整余地。
当LEADING Hint中指定的表并不能做为目标SQL的链接过程当中的驱动表或者驱动结果集时,Oracle会忽略该Hint。
格式以下:
/*+ LEADING(目标表1 目标表2 …… 目标表n) */
使用范例:
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;
实例:
--不使用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中顺序一致。
参考《基于Oracle的SQL优化》
官方文档:http://docs.oracle.com/cd/E11882_01/server.112/e41573/hintsref.htm#PFGRF005