阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

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

187次阅读
没有评论

共计 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

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计19000字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中