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

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

362次阅读
没有评论

共计 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、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19348
评论数
4
阅读量
7804724
文章搜索
热门文章
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板 1Panel:小白轻松构建 Web 服务与面板加固指南 哈喽,我是星哥,经常有人问我不...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地 大家好,我是星哥,今天教大家在飞牛 NA...
【开源神器】微信公众号内容单篇、批量下载软件

【开源神器】微信公众号内容单篇、批量下载软件

【开源神器】微信公众号内容单篇、批量下载软件 大家好,我是星哥,很多人都希望能高效地保存微信公众号的文章,用于...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
我用AI做了一个1978年至2019年中国大陆企业注册的查询网站

我用AI做了一个1978年至2019年中国大陆企业注册的查询网站

我用 AI 做了一个 1978 年至 2019 年中国大陆企业注册的查询网站 最近星哥在 GitHub 上偶然...
星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的 NAS 中! 大家对「数据安全感」的需求越来越高 ...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
如何免费使用强大的Nano Banana Pro?附赠邪修的用法

如何免费使用强大的Nano Banana Pro?附赠邪修的用法

如何免费使用强大的 Nano Banana Pro?附赠邪修的用法 前言 大家好,我是星哥,今天来介绍谷歌的 ...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

仅2MB大小!开源硬件监控工具:Win11 无缝适配,CPU、GPU、网速全维度掌控

还在忍受动辄数百兆的“全家桶”监控软件?后台偷占资源、界面杂乱冗余,想查个 CPU 温度都要层层点选? 今天给...
你的云服务器到底有多强?宝塔跑分告诉你

你的云服务器到底有多强?宝塔跑分告诉你

你的云服务器到底有多强?宝塔跑分告诉你 为什么要用宝塔跑分? 宝塔跑分其实就是对 CPU、内存、磁盘、IO 做...
每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年 0.99 刀,拿下你的第一个顶级域名,详细注册使用 前言 作为长期折腾云服务、域名建站的老玩家,星哥一直...