1. 程式人生 > 其它 >Oracle中Hint被忽略的幾種常見情形

Oracle中Hint被忽略的幾種常見情形

Oracle中Hint被忽略的幾種常見情形

作者:hbxztc時間: 2021-02-05 09:26:55 標籤:oraclehint失效
【摘要】Hint可以影響優化器對於執行計劃的選擇,但這種影響不是強制性的,優化器在某些情況下可能會忽略目標SQL中的Hint。由於各種原因導致Hint被Oracle忽略後,Oracle並不會給出任何提示或者警告,更不會報錯,目標SQL依然可以正常執行,這也符合Hint實際上是一種特殊註釋的身份。註釋本來就是可有可無的東西,不應該因為它的存在而而導致原先在沒有Hint時可以正常執行的SQL因為加了Hi...

Hint可以影響優化器對於執行計劃的選擇,但這種影響不是強制性的,優化器在某些情況下可能會忽略目標SQL中的Hint。由於各種原因導致Hint被Oracle忽略後,Oracle並不會給出任何提示或者警告,更不會報錯,目標SQL依然可以正常執行,這也符合Hint實際上是一種特殊註釋的身份。註釋本來就是可有可無的東西,不應該因為它的存在而而導致原先在沒有Hint時可以正常執行的SQL因為加了Hint後而變得不能正常執行。

下面來看幾種Hint被Oracle忽略的常見情形。

1 使用的Hint有語法或者拼寫錯誤

一旦使用的Hint中有語法或者拼寫錯誤,Oracle就會忽略該Hint,看幾個示例SQL:

  1. select /*+ ind(emp pk_emp) */* from emp;

  2. select /*+ index(emp pk_emp */* from emp;

  3. select /* + index(emp pk_emp) */* from emp;

  4. select */*+ index(emp pk_emp) */ from emp;

  5. select /*+ index(scott.emp pk_emp) */* from emp;

  6. select /*+ index(emp pk_emp) */* from emp e;

  7. select /*+ index(emp emp_pk) */* from emp;

  8. 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:

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:

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優化》