Oracle中Hint被忽略的几种常见情形

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的执行计划

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/4e07d46c3f6e3ae83b5f2a1e4c4ce3df.html