共计 19000 个字符,预计需要花费 48 分钟才能阅读完成。
Hint 可以影响优化器对于执行计划的选择,但这种影响不是强制性的,优化器在某些情况下可能会忽略目标 SQL 中的 Hint。由于各种原因导致 Hint 被 Oracle 忽略后,Oracle 并不会给出任何提示或者警告,更不会报错,目标 SQL 依然可以正常运行,这也符合 Hint 实际上是一种特殊注释的身份。注释本来就是可有可无的东西,不应该因为它的存在而而导致原先在没有 Hint 时可以正常执行的 SQL 因为加了 Hint 后而变得不能正常执行。
下面来看几种 Hint 被 Oracle 忽略的常见情形。
1 使用的 Hint 有语法或者拼写错误
一旦使用的 Hint 中有语法或者拼写错误,Oracle 就会忽略该 Hint,看几个示例 SQL:
select /*+ ind(emp pk_emp) */* from emp;
select /*+ index(emp pk_emp */* from emp;
select /* + index(emp pk_emp) */* from emp;
select */*+ index(emp pk_emp) */ from emp;
select /*+ index(scott.emp pk_emp) */* from emp;
select /*+ index(emp pk_emp) */* from emp e;
select /*+ index(emp emp_pk) */* from emp;
select /*+ full(t2) */ t1.ename,t1.deptno from emp t1 where t1.deptno in (select t2.deptno from detp t where t2.loc=’CHICAGO’);
实际上,上述 8 条 SQL 中的 Hint 都是无效的,它们都会被 Oracle 忽略。
1 是因为关键字应该是 ”index” 而不是 ”ind”
2 是因为漏掉了一个右括号
3 是因为 Hint 中第一个 * 和 + 之间出现了空格
4 是因为 Hint 出现的位置不对,它应该出现在 * 前面
5 是因为 emp 表前面带上了 SCHEME 名称
6 是因为没有 emp 表的别名
7 是因为索引名称写错了
8 是因为 Hint 跨了 Query Block。Hint 生效的范围公限于它本身所在的 Query Block,如果将某个 Hint 生将范围扩展到它所在的 Query Block 之外而又没在该 Hint 中指定其生效的 Query Block 名称的话,Oracle 就会忽略该 Hint。
2 使用的 Hint 无效
即使语法是正确的,但如果由于某种原因导致 Oracle 认为这个 Hint 无效,则 Oracle 还是会忽略该 Hint。
看几个实例
scott@TEST>set autotrace traceonly
scott@TEST>select /*+ index(dept idx_dept_loc) */ deptno,dname from dept where loc=’CHICAGO’;
Execution Plan
———————————————————-
Plan hash value: 492093765
——————————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————————–
| 0 | SELECT STATEMENT | | 10 | 300 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| DEPT | 10 | 300 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_DEPT_LOC | 4 | | 1 (0)| 00:00:01 |
——————————————————————————————–
……
从上面的输出可以看出,上面的 SQL 的执行计划走的是对索引 IDX_DEPT_LOC 的索引范围扫描,说明 Hint 生效了,但是如果把 where 条件替换为与索引 IDX_DEPT_LOC 毫不相关的 deptno=30,再来看执行情况
scott@TEST>select /*+ index(dept idx_dept_loc) */ deptno,dname from dept where deptno=30;
Execution Plan
———————————————————-
Plan hash value: 2852011669
—————————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————
| 0 | SELECT STATEMENT | | 1 | 22 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 22 | 2 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 1 (0)| 00:00:01 |
—————————————————————————————
……
从上面的输出可以看出,执行计划走的是对主键 PK_DEPT 的 INDEX UNIQUE SCAN,面不是 Hint 里的 IDX_DEPT_LOC。这就说明 Hint 在这个 SQL 失效了。
即使不改 where 条件,如果把索引 IDX_DEPT_LOC 删除,这个 Hint 也会失效:
scott@TEST>drop index idx_dept_loc;
Index dropped.
scott@TEST>select /*+ index(dept idx_dept_loc) */ deptno,dname from dept where loc=’CHICAGO’;
Execution Plan
———————————————————-
Plan hash value: 3383998547
————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————–
| 0 | SELECT STATEMENT | | 10 | 300 | 29 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| DEPT | 10 | 300 | 29 (0)| 00:00:01 |
————————————————————————–
从上面的执行计划可以看出走的是对表 DEPT 的 TABLE ACCESS FULL,Hint 也是失效的。
再来看一个使用组合 Hint 的例子,先看如下 SQL 的执行计划
scott@TEST>select /*+ full(dept) parallel(dept 2) */ deptno from dept;
Execution Plan
———————————————————-
Plan hash value: 587379989
————————————————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | TQ |IN-OUT| PQ Distrib |
————————————————————————————————————–
| 0 | SELECT STATEMENT | | 1000 | 13000 | 16 (0)| 00:00:01 | | | |
| 1 | PX COORDINATOR | | | | | | | | |
| 2 | PX SEND QC (RANDOM)| :TQ10000 | 1000 | 13000 | 16 (0)| 00:00:01 | Q1,00 | P->S | QC (RAND) |
| 3 | PX BLOCK ITERATOR | | 1000 | 13000 | 16 (0)| 00:00:01 | Q1,00 | PCWC | |
| 4 | TABLE ACCESS FULL| DEPT | 1000 | 13000 | 16 (0)| 00:00:01 | Q1,00 | PCWP | |
————————————————————————————————————–
……
从上面输出内容可以看出,现在是对表 DEPT 做的并行全表扫描,说明组合 Hint 中的两个都生效了,这个 Hint 的含义是既要全表扫描又要并行访问表 DEPT,两者不矛盾,因为全表扫描可以并行执行。再看如下的 SQL:
scott@TEST>select /*+ index(dept pk_dept) parallel(dept 2) */ deptno from dept;
4 rows selected.
Execution Plan
———————————————————-
Plan hash value: 2913917002
—————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————-
| 0 | SELECT STATEMENT | | 1000 | 13000 | 26 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_DEPT | 1000 | 13000 | 26 (0)| 00:00:01 |
—————————————————————————-
……
现在 SQL 走的是对索引 PK_DEPT 的索引全扫描,但是串行的,说明 Hint 中的 parallel(dept 2)失效了,因为表 DEPT 上的主键索引 PK_DEPT 不是分区索引,而对于非分区索引而言,索引范围扫描或索引全扫描并不能并行执行,所以上述组合 Hint 中忽略了 parallel(dept 2)。
再看一个 HASH JOIN 的例子:
下面的 SQL 中 use_hash 的 Hint 是生效的:
scott@TEST>select /*+ use_hash(t1) */ t1.empno,t1.empno,t2.loc from emp t1,dept t2 where t1.deptno=t2.deptno and t2.loc=’CHICAGO’;
6 rows selected.
Execution Plan
———————————————————-
Plan hash value: 615168685
—————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————
| 0 | SELECT STATEMENT | | 5 | 185 | 7 (15)| 00:00:01 |
|* 1 | HASH JOIN | | 5 | 185 | 7 (15)| 00:00:01 |
|* 2 | TABLE ACCESS FULL| DEPT | 1 | 11 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 14 | 364 | 3 (0)| 00:00:01 |
————————————————————————–
–
但是如果把 SQL 修改为如下则 use_hash 的 Hint 就会被忽略
scott@TEST>select /*+ use_hash(t1) */ t1.empno,t1.empno,t2.loc from emp t1,dept t2 where t1.deptno>t2.deptno and t2.loc=’CHICAGO’;
no rows selected
Execution Plan
———————————————————-
Plan hash value: 4192419542
—————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————
| 0 | SELECT STATEMENT | | 1 | 37 | 6 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 37 | 6 (0)| 00:00:01 |
|* 2 | TABLE ACCESS FULL| DEPT | 1 | 11 | 3 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| EMP | 1 | 26 | 3 (0)| 00:00:01 |
—————————————————————————
从上面的执行计划中看出 use_hash 确实是被 Oracle 忽略了,这是因为哈希连接只适用于等值连接条件,不等值的连接条件对哈希连接而言是没有意义的,所以上述 Hint 就被 Oracle 忽略了。
3 使用的 Hint 自相矛盾
如果使用的组合 Hint 是自相矛盾的,则这些自相矛盾的 Hint 都会被 Oracle 忽略。但 Oracle 只会将自相矛盾的 Hint 全部忽略掉,但如果使用的组合 Hint 中还有其他有效的 Hint,则这些有效 Hint 不受影响。
看一个使用自相矛盾 Hint 的实例,先执行单个 Hint 的 SQL
scott@TEST>select /*+ index_ffs(dept pk_dept)*/ deptno from dept;
4 rows selected.
Execution Plan
———————————————————-
Plan hash value: 2578398298
——————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————–
| 0 | SELECT STATEMENT | | 4 | 12 | 2 (0)| 00:00:01 |
| 1 | INDEX FAST FULL SCAN| PK_DEPT | 4 | 12 | 2 (0)| 00:00:01 |
——————————————————————————–
……
scott@TEST>select /*+ full(dept)*/ deptno from dept;
4 rows selected.
Execution Plan
———————————————————-
Plan hash value: 3383998547
————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
————————————————————————–
| 0 | SELECT STATEMENT | | 4 | 12 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DEPT | 4 | 12 | 3 (0)| 00:00:01 |
————————————————————————–
从上面的输出可以看出单独使用上面的两个 Hint 都能被 Oracle 生效,但如果这两个 Hint 合并到一起使用就不是那么回事了:
scott@TEST>select /*+ index_ffs(dept pk_dept) full(dept)*/ deptno from dept;
4 rows selected.
Execution Plan
———————————————————-
Plan hash value: 2913917002
—————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————-
| 0 | SELECT STATEMENT | | 4 | 12 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_DEPT | 4 | 12 | 1 (0)| 00:00:01 |
—————————————————————————-
从上面的输出可以看出执行计划没有走 Hint 中指定的执行计划,而是对主键索引 PK_DEPT 做的是 INDEX FULL SCAN 这说明 Hint 中的两个都失效了。
再来看下面的例子:
scott@TEST>select /*+ index_ffs(dept pk_dept) full(dept) cardinality(dept 1000) */ deptno from dept;
4 rows selected.
Execution Plan
———————————————————-
Plan hash value: 2913917002
—————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————-
| 0 | SELECT STATEMENT | | 1000 | 3000 | 1 (0)| 00:00:01 |
| 1 | INDEX FULL SCAN | PK_DEPT | 1000 | 3000 | 1 (0)| 00:00:01 |
—————————————————————————-
从上面的输出可以看出执行计划走的仍然是对主键索引 PK_DEPT 做的是 INDEX FULL SCAN,但是做 INDEX FULL SCAN 反回结果集的 cardinality 从原来的 4 变为了 1000,说明 cardinality(dept 1000)生效了,也验证了如果使用的组合 Hint 中还有其他有效的 Hint,则这些有效 Hint 不受影响。
4 使用的 Hint 受到了查询转换的干扰
有时候,查询转换也会导致相关的 Hint 失效,即 Hint 被 Oracle 忽略还可能是因为受到了查询转换的干扰。
下面来看一个因为使用了查询转换而导致相关 Hint 被 Oracle 忽略掉的实例。
创建一个测试表 jobs
scott@TEST>create table jobs as select empno,job from emp;
Table created.
构造一个 SQL
select /*+ ordered cardinality(e 100) */
e.ename, j.job, e.sal, v.avg_sal
from emp e,
jobs j,
(select /*+ merge */
e.deptno, avg(e.sal) avg_sal
from emp e, dept d
where d.loc = ‘chicago’
and d.deptno = e.deptno
group by e.deptno) v
where e.empno = j.empno
and e.deptno = v.deptno
and e.sal > v.avg_sal
order by e.ename;
上面的 SQL 是两个表 (EMP 和 JOBS) 和内嵌视图 V 关联的 SQL,其中内嵌视图 V 又是由表 EMP 和 DEPT 关联后得到的。在此 SQL 中使用了三个 Hint,其中 merge 用于让内嵌视图 V 做视图合并,ordered 表示上述 SQL 在执行时表 EMP、JOBS 和内嵌视图 V 的连接顺序应该和它们在该 SQL 的 SQL 文本中出现的顺序一致,即它们应该是按照从左至右的顺序依次做表连接。
如果上述三个 Hint 都生效的话,那目标 SQL 的执行计划中应该不会出现关键字“VIEW”(表示做了视图合并,体现了 Merge Hint 的作用),表 EMP、JOBS 和内嵌视图 V 的连接应该会变成表 EMP、JOBS 和内嵌视图 V 所对应的基表 EMP 和 DEPT 的连接,且连接的先后顺序应该是 EMP->JOBS-> 内嵌视图 V 所对应的基表 EMP 和 DEPT(体现了 Ordered Hint 的作用),外围查询中表 EMP 的扫描结果所对应的 Cardinality 的值应该是 100(体现了 Cardinality Hint 的作用)。
现在看一下实际情况,执行上面的 SQL:
1 scott@TEST>select /*+ ordered cardinality(e 100) */
2 e.ename, j.job, e.sal, v.avg_sal
3 from emp e,
4 jobs j,
5 (select /*+ merge */
6 e.deptno, avg(e.sal) avg_sal
7 from emp e, dept d
8 where d.loc = ‘chicago’
9 and d.deptno = e.deptno
10 group by e.deptno) v
11 where e.empno = j.empno
12 and e.deptno = v.deptno
13 and e.sal > v.avg_sal
14 order by e.ename;
no rows selected
Execution Plan
———————————————————-
Plan hash value: 930847561
——————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————-
| 0 | SELECT STATEMENT | | 156 | 19656 | 15 (20)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | SORT GROUP BY | | 156 | 19656 | 15 (20)| 00:00:01 |
|* 3 | HASH JOIN | | 156 | 19656 | 14 (15)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | DEPT | 1 | 11 | 3 (0)| 00:00:01 |
|* 5 | HASH JOIN | | 467 | 53705 | 10 (10)| 00:00:01 |
| 6 | TABLE ACCESS FULL | EMP | 14 | 364 | 3 (0)| 00:00:01 |
|* 7 | HASH JOIN | | 100 | 8900 | 7 (15)| 00:00:01 |
| 8 | TABLE ACCESS FULL| EMP | 100 | 5800 | 3 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL| JOBS | 14 | 434 | 3 (0)| 00:00:01 |
——————————————————————————-
从上面的执行计划可以看出,确实没有出现关键字“VIEW”,表 EMP 的扫描结果所对应的 Cardinality 的值确实是 100,但连接顺序不是上面提到的顺序,而是先选择的表 DEPT。这说明上述三个 Hint 中的 Merge Hint 和 Cardinality Hint 生效了,但 Ordered Hint 被 Oracle 忽略了。这是因为受到了查询转换的干扰(对内嵌视图 V 做视图合并是一种查询转换)。
为了证明上述 SQL 的 Ordered Hint 被 Oracle 忽略是因为受到了查询转换的干扰,现在将内嵌视图 V 中的 merge 替换为 no_merge(不让内嵌视图做视图合并),再次执行该 SQL:
1 scott@TEST>select /*+ ordered cardinality(e 100) */
2 e.ename, j.job, e.sal, v.avg_sal
3 from emp e,
4 jobs j,
5 (select /*+ no_merge */
6 e.deptno, avg(e.sal) avg_sal
7 from emp e, dept d
8 where d.loc = ‘chicago’
9 and d.deptno = e.deptno
10 group by e.deptno) v
11 where e.empno = j.empno
12 and e.deptno = v.deptno
13 and e.sal > v.avg_sal
14 order by e.ename;
no rows selected
Execution Plan
———————————————————-
Plan hash value: 2898000699
——————————————————————————————–
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
——————————————————————————————–
| 0 | SELECT STATEMENT | | 8 | 728 | 14 (22)| 00:00:01 |
| 1 | SORT ORDER BY | | 8 | 728 | 14 (22)| 00:00:01 |
|* 2 | HASH JOIN | | 8 | 728 | 13 (16)| 00:00:01 |
|* 3 | HASH JOIN | | 100 | 6500 | 7 (15)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMP | 100 | 4600 | 3 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL | JOBS | 14 | 266 | 3 (0)| 00:00:01 |
| 6 | VIEW | | 5 | 130 | 6 (17)| 00:00:01 |
| 7 | HASH GROUP BY | | 5 | 185 | 6 (17)| 00:00:01 |
| 8 | MERGE JOIN | | 5 | 185 | 6 (17)| 00:00:01 |
|* 9 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 11 | 2 (0)| 00:00:01 |
| 10 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 11 | SORT JOIN | | 14 | 364 | 4 (25)| 00:00:01 |
| 12 | TABLE ACCESS FULL | EMP | 14 | 364 | 3 (0)| 00:00:01 |
——————————————————————————————–
从上面的执行计划中可以看出,出现了“VIEW”关键字,说明没有做视图合并,表 EMP 对就的 Cardinality 为 100,连接顺序与前面预想的一致,这说明在禁掉了查询转换后之前被忽略的 Ordered Hint 又生效了。
5 使用的 Hint 受到了保留关键字的干扰
Oracle 在解析 Hint 时,是按照从左到右的顺序进行的,如果遇到的词是 Oracle 的保留关键字,则 Oracle 将忽略这个词以及之后的所有词;如果遇到词既不是关键字也不是 Hint,就忽略该词;如果遇到的词是有效的 Hint,那么 Oracle 就会保留该 Hing。
正是由于上述 Oracle 解析 Hint 的原则,保留关键字也可能导致相关的 Hint 失效。
Oracle 的���留关键字可以从视图 V$RESERVED_WORDS 中查到,从下面的查询结果可以看到 ’,’、’COMMENT’、’IS’ 都是保留关键字,但“THIS”不是
scott@TEST>select keyword,length from v$reserved_words where keyword in (‘,’,’THIS’,’IS’,’COMMENT’);
KEYWORD LENGTH
———- ———-
, 1
COMMENT 7
IS 2
下面来看一个保留关键字导致 Hint 失效的实例,执行下面的 SQL
scott@TEST>select t1.empno,t1.empno,t2.loc from emp t1,dept t2 where t1.deptno=t2.deptno;
14 rows selected.
Execution Plan
———————————————————-
Plan hash value: 844388907
—————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————-
| 0 | SELECT STATEMENT | | 14 | 518 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN | | 14 | 518 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 44 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 14 | 364 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL | EMP | 14 | 364 | 3 (0)| 00:00:01 |
—————————————————————————————-
从执行计划上看走的是 MERGE SORT JOIN,对 SQL 加入如下 Hint 并执行:
scott@TEST>select /*+ use_hash(t1) index(t2 pk_dept) */ t1.empno,t1.empno,t2.loc from emp t1,dept t2 where t1.deptno=t2.deptno;
14 rows selected.
Execution Plan
———————————————————-
Plan hash value: 2622742753
—————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————-
| 0 | SELECT STATEMENT | | 14 | 518 | 6 (17)| 00:00:01 |
|* 1 | HASH JOIN | | 14 | 518 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 44 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMP | 14 | 364 | 3 (0)| 00:00:01 |
—————————————————————————————-
从上面的执行计划中可以看出 Hint 中的两个都生效了,emp 做 HASH JOIN 的被驱动表,对 DEPT 表做使用索引 PK_DEPT。现在对 Hint 加入 ’,’,查看执行情况:
scott@TEST>select /*+ use_hash(t1) , index(t2 pk_dept) */ t1.empno,t1.empno,t2.loc from emp t1,dept t2 where t1.deptno=t2.deptno;
14 rows selected.
Execution Plan
———————————————————-
Plan hash value: 615168685
—————————————————————————
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————
| 0 | SELECT STATEMENT | | 14 | 518 | 7 (15)| 00:00:01 |
|* 1 | HASH JOIN | | 14 | 518 | 7 (15)| 00:00:01 |
| 2 | TABLE ACCESS FULL| DEPT | 4 | 44 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| EMP | 14 | 364 | 3 (0)| 00:00:01 |
—————————————————————————
从执行计划中可以看出,仍然走的是 HASH JOIN 但是 index(t2 pk_dept)失效了。因为 ’,’ 是 Oracle 的保留关键字,所以 ’,’ 后面的 index(t2 pk_dept)失效了,再修改 Hint 如下并执行 SQL:
scott@TEST>select /*+ comment use_hash(t1) index(t2 pk_dept) */ t1.empno,t1.empno,t2.loc from emp t1,dept t2 where t1.deptno=t2.deptno;
14 rows selected.
Execution Plan
———————————————————-
Plan hash value: 844388907
—————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————-
| 0 | SELECT STATEMENT | | 14 | 518 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN | | 14 | 518 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 44 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 14 | 364 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL | EMP | 14 | 364 | 3 (0)| 00:00:01 |
—————————————————————————————-
从执行计划中看出,现在走的是跟一开始的执行计划一样,说明 Hint 中的两个都失效了,因为这两个都在 Oracle 保留关键字 comment 后面。再修改 Hint 如下再次执行 SQL:
scott@TEST>select /*+ this use_hash(t1) index(t2 pk_dept) */ t1.empno,t1.empno,t2.loc from emp t1,dept t2 where t1.deptno=t2.deptno;
14 rows selected.
Execution Plan
———————————————————-
Plan hash value: 2622742753
—————————————————————————————-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
—————————————————————————————-
| 0 | SELECT STATEMENT | | 14 | 518 | 6 (17)| 00:00:01 |
|* 1 | HASH JOIN | | 14 | 518 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 44 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMP | 14 | 364 | 3 (0)| 00:00:01 |
—————————————————————————————-
现在执行计划又走出了 Hint 指定的样子,说明两个都生效了,这是因为 this 不是 Oracle 保留关键字。
以上介绍了 5 种 Hint 被 Oracle 忽略的情况,在实例使用过程中一定要注意使用方法,使用正确有效的 Hint 来提升 SQL 执行效率,避免 Hint 被 Oracle 忽略。
基于 Oracle 的 SQL 优化(PDF 完整扫描版) http://www.linuxidc.com/Linux/2017-02/140521.htm
更多 Oracle 相关信息见Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-03/142127.htm