使用Hint時的注意事項


 

在使用Hint時需要注意的一點是,並非任何時刻Hint都起作用。 導致HINT 失效的原因有如下2點:

(1) 如果CBO 認為使用Hint 會導致錯誤的結果時,Hint將被忽略。

如索引中的記錄因為空值而和表的記錄不一致時,結果就是錯誤的,會忽略hint。

(2) 如果表中指定了別名,那么Hint中也必須使用別名,否則Hint也會忽略。

Select /*+full(a)*/ *  from t a; -- 使用hint

Select /*+full(t) */  *  from t a; --不使用hint

根據hint的功能,可以分成如下幾類:

Hint Hint 語法
優化器模式提示 ALL_ROWS Hint
  FIRST_ROWS Hint
  RULE Hint
訪問路徑提示 CLUSTER Hint
  FULL Hint
  HASH Hint
  INDEX Hint
  NO_INDEX Hint
  INDEX_ASC Hint
  INDEX_DESC Hint
  INDEX_COMBINE Hint
  INDEX_FFS Hint
  INDEX_SS Hint
  INDEX_SS_ASC Hint
  INDEX_SS_DESC Hint
  NO_INDEX_FFS Hint
  NO_INDEX_SS Hint
  ORDERED Hint
  LEADING Hint
  USE_HASH Hint
  NO_USE_HASH Hint
表連接順序提示 USE_MERGE Hint
  NO_USE_MERGE Hint
  USE_NL Hint
  USE_NL_WITH_INDEX Hint
  NO_USE_NL Hint
表關聯方式提示 PARALLEL Hint
  NO_PARALLEL Hint
  PARALLEL_INDEX Hint
  NO_PARALLEL_INDEX Hint
  PQ_DISTRIBUTE Hint
並行執行提示 FACT Hint
  NO_FACT Hint
  MERGE Hint
  NO_MERGE Hint
  NO_EXPAND Hint
  USE_CONCAT Hint
查詢轉換提示 REWRITE Hint
  NO_REWRITE Hint
  UNNEST Hint
  NO_UNNEST Hint
  STAR_TRANSFORMATION Hint
  NO_STAR_TRANSFORMATION Hint
  NO_QUERY_TRANSFORMATION Hint
  APPEND Hint
  NOAPPEND Hint
  CACHE Hint
  NOCACHE Hint
  CURSOR_SHARING_EXACT Hint
其他Hint DRIVING_SITE Hint
  DYNAMIC_SAMPLING Hint
  PUSH_PRED Hint
  NO_PUSH_PRED Hint
  PUSH_SUBQ Hint
  NO_PUSH_SUBQ Hint
  PX_JOIN_FILTER Hint
  NO_PX_JOIN_FILTER Hint
  NO_XML_QUERY_REWRITE Hint
  QB_NAME Hint
  MODEL_MIN_ANALYSIS Hint

一. 和優化器相關的Hint

Oracle 允許在系統級別,會話級別和SQL中(hint)優化器類型:

系統級別:
1: SQL>alter system set optimizer_mode=all_rows;
會話級別:
SQL>alter system set optimizer_mode=all_rows;
關於優化器,參考:

Oracle Optimizer CBO RBO

 

1.1 ALL_ROWS 和FIRST_ROWS(n) -- CBO 模式

對於OLAP系統,這種系統中通常都是運行一些大的查詢操作,如統計,報表等任務。 這時優化器模式應該選擇ALL_ROWS. 對於一些分頁顯示的業務,就應該用FIRST_ROWS(n)。 如果是一個系統上運行這兩種業務,那么就需要在SQL 用hint指定優化器模式。

如:

SQL> select /* + all_rows*/  * from dave;

SQL> select /* + first_rows(20)*/ * from dave;

1.2 RULE Hint -- RBO 模式

盡管Oracle 10g已經棄用了RBO,但是仍然保留了這個hint。 它允許在CBO 模式下使用RBO 對SQL 進行解析。

如:

SQL> show parameter optimizer_mode

NAME TYPE VALUE

------------------------------------ ----------- ------------------------------

optimizer_mode string ALL_ROWS

SQL> set autot trace exp;

SQL> select /*+rule */ * from dave;

執行計划

----------------------------------------------------------

Plan hash value: 3458767806

----------------------------------

| Id | Operation | Name |

----------------------------------

| 0 | SELECT STATEMENT | |

| 1 | TABLE ACCESS FULL| DAVE |

----------------------------------

Note

-----

- rule based optimizer used (consider using cbo) -- 這里提示使用RBO

SQL>

二. 訪問路徑相關的Hint

這一部分hint 將直接影響SQL 的執行計划,所以在使用時需要特別小心。 該類Hint對DBA分析SQL性能非常有幫助,DBA 可以讓SQL使用不同的Hint得到不同的執行計划,通過比較不同的執行計划來分析當前SQL性能。

2.1 FULL Hint

該Hint告訴優化器對指定的表通過全表掃描的方式訪問數據。

示例:

SQL> select /*+full(dave) */ * from dave;

要注意,如果表有別名,在hint里也要用別名, 這點在前面已經說明。

2.2 INDEX Hint

Index hint 告訴優化器對指定的表通過索引的方式訪問數據,當訪問索引會導致結果集不完整時,優化器會忽略這個Hint。

示例:

SQL> select /*+index(dave index_dave) */ * from dave where id>1;

謂詞里有索引字段,才會用索引。

2.3 NO_INDEX Hint

No_index hint 告訴優化器對指定的表不允許使用索引。

示例:

SQL> select /*+no_index(dave index_dave) */ * from dave where id>1;

2.4 INDEX_DESC Hint

該Hint 告訴優化器對指定的索引使用降序方式訪問數據,當使用這個方式會導致結果集不完整時,優化器將忽略這個索引。

示例:

SQL> select /*+index_desc(dave index_dave) */ * from dave where id>1;

2.5 INDEX_COMBINE Hint

該Hint告訴優化器強制選擇位圖索引,當使用這個方式會導致結果集不完整時,優化器將忽略這個Hint。

示例:

SQL> select /*+ index_combine(dave index_bm) */ * from dave;

2.6 INDEX_FFS Hint

該hint告訴優化器以INDEX_FFS(INDEX Fast Full Scan)的方式訪問數據。當使用這個方式會導致結果集不完整時,優化器將忽略這個Hint。

示例:

SQL> select /*+ index_ffs(dave index_dave) */ id from dave where id>0;

2.7 INDEX_JOIN Hint

索引關聯,當謂詞中引用的列上都有索引時,可以通過索引關聯的方式來訪問數據。

示例:

SQL> select /*+ index_join(dave index_dave index_bm) */ * from dave where id>0 and name='安徽安慶';

2.8 INDEX_SS Hint

該Hint強制使用index skip scan 的方式訪問索引,從Oracle 9i開始引入這種索引訪問方式,當在一個聯合索引中,某些謂詞條件並不在聯合索引的第一列時(或者謂詞並不在聯合索引的第一列時),可以通過index skip scan 來訪問索引獲得數據。 當聯合索引第一列的唯一值很小時,使用這種方式比全表掃描效率要高。當使用這個方式會導致結果集不完整時,優化器將忽略這個Hint。

示例:

SQL> select /*+ index_ss(dave index_union) */ * from dave where id>0;

三. 表關聯順序的Hint

表之間的連接方式有三種。 具體參考blog:

多表連接的三種方式詳解 HASH JOIN MERGE JOIN NESTED LOOP

 

3.1 LEADING hint

在一個多表關聯的查詢中,該Hint指定由哪個表作為驅動表,告訴優化器首先要訪問哪個表上的數據。

示例:

SQL> select /*+leading(t1,t) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

SQL> select /*+leading(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

--------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti

--------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 14 | 812 | 6 (17)| 00

| 1 | MERGE JOIN | | 14 | 812 | 6 (17)| 00

| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 4 | 80 | 2 (0)| 00

| 3 | INDEX FULL SCAN | PK_DEPT | 4 | | 1 (0)| 00

|* 4 | SORT JOIN | | 14 | 532 | 4 (25)| 00

| 5 | TABLE ACCESS FULL | EMP | 14 | 532 | 3 (0)| 00

--------------------------------------------------------------------------------

3.2 ORDERED Hint

該hint 告訴Oracle 按照From后面的表的順序來選擇驅動表,Oracle 建議在選擇驅動表上使用Leading,它更靈活一些。

SQL> select /*+ordered */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

四. 表關聯操作的Hint

4.1 USE_HASH,USE_NL,USE_MERGE hint

表之間的連接方式有三種。 具體參考blog:

多表連接的三種方式詳解 HASH JOIN MERGE JOIN NESTED LOOP

 

這三種關聯方式是多表關聯中主要使用的關聯方式。 通常來說,當兩個表都比較大時,Hash Join的效率要高於嵌套循環(nested loops)的關聯方式。

Hash join的工作方式是將一個表(通常是小一點的那個表)做hash運算,將列數據存儲到hash列表中,從另一個表中抽取記錄,做hash運算,到hash 列表中找到相應的值,做匹配。

Nested loops 工作方式是從一張表中讀取數據,訪問另一張表(通常是索引)來做匹配,nested loops適用的場合是當一個關聯表比較小的時候,效率會更高。

Merge Join 是先將關聯表的關聯列各自做排序,然后從各自的排序表中抽取數據,到另一個排序表中做匹配,因為merge join需要做更多的排序,所以消耗的資源更多。 通常來講,能夠使用merge join的地方,hash join都可以發揮更好的性能。

USE_HASH,USE_NL,USE_MERGE 這三種hint 就是告訴優化器使用哪種關聯方式。

示例如下:

SQL> select /*+use_hash(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

SQL> select /*+use_nl(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

SQL> select /*+use_merge(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

4.2 NO_USE_HASH,NO_USE_NL,NO_USE_MERGE HINT

分別禁用對應的關聯方式。

示例:

SQL> select /*+no_use_merge(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

SQL> select /*+no_use_nl(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

SQL> select /*+no_use_hash(t,t1) */ * from scott.dept t,scott.emp t1 where t.deptno=t1.deptno;

五. 並行執行相關的Hint

5.1 PARALLEL HINT

指定SQL 執行的並行度,這個值會覆蓋表自身設定的並行度,如果這個值為default,CBO使用系統參數值。

示例:

SQL> select /*+parallel(t 4) */ * from scott.dept t;

關於表的並行度,我們在創建表的時候可以指定,如:

SQL> CREATE TABLE Anqing

2 (

3 name VARCHAR2 (10)

4 )

5 PARALLEL 2;

表已創建。

SQL> select degree from all_tables where table_name = 'ANQING'; -- 查看表的並行度

DEGREE

--------------------

2

SQL> alter table anqing parallel(degree 3); -- 修改表的並行度

表已更改。

SQL> select degree from all_tables where table_name = 'ANQING';

DEGREE

--------------------

3

SQL> alter table anqing noparallel; -- 取消表的並行度

表已更改。

SQL> select degree from all_tables where table_name = 'ANQING';

DEGREE

--------------------

1

5.2 NO_PARALLEL HINT

在SQL中禁止使用並行。

示例:

SQL> select /*+ no_parallel(t) */ * from scott.dept t;

六. 其他方面的一些Hint

6.1 APPEND HINT

提示數據庫以直接加載的方式(direct load)將數據加載入庫。

示例:

Insert /*+append */ into t as select * from all_objects;

這個hint 用的比較多。 尤其在插入大量的數據,一般都會用此hint。

Oracle 插入大量數據

 

6.2 DYNAMIC_SAMPLING HINT

提示SQL 執行時動態采樣的級別。 這個級別從0-10,它將覆蓋系統默認的動態采樣級別。

示例:

SQL> select /*+ dynamic_sampling(t 2) */ * from scott.emp t where t.empno>0;

6.3 DRIVING_SITE HINT

這個提示在分布式數據庫操作中比較有用,比如我們需要關聯本地的一張表和遠程的表:

Select /* + driving_site(departmetns) */ * from employees,departments@dblink where

employees .department_id = departments.department_id;

如果沒有這個提示,Oracle 會在遠端機器上執行departments 表查詢,將結果送回本地,再和employees表關聯。 如果使用driving_site(departments), Oracle將查詢本地表employees,將結果送到遠端,在遠端將數據庫上的表與departments關聯,然后將查詢的結果返回本地。

如果departments查詢結果很大,或者employees查詢結果很小,並且兩張表關聯之后的結果集很小,那么就可以考慮把本地的結果集發送到遠端。 在遠端執行完后,在將較小的最終結果返回本地。

6.4 CACHE HINT

在全表掃描操作中,如果使用這個提示,Oracle 會將掃描的到的數據塊放到LRU(least recently Used: 最近很少被使用列表,是Oracle 判斷內存中數據塊活躍程度的一個算法)列表的最被使用端(數據塊最活躍端),這樣數據塊就可以更長時間地駐留在內存當中。 如果有一個經常被訪問的小表,這個設置會提高查詢的性能;同時CACHE也是表的一個屬性,如果設置了表的cache屬性,它的作用和hint一樣,在一次全表掃描之后,數據塊保留在LRU列表的最活躍端。

示例:

SQL> select /*+full(t) cache (t) */ * from scott.emp;

小結:

對於DBA來講,掌握一些Hint操作,在實際性能優化中有很大的好處,比如我們發現一條SQL的執行效率很低,首先我們應當查看當前SQL的執行計划,然后通過hint的方式來改變SQL的執行計划,比較這兩條SQL 的效率,作出哪種執行計划更優,如果當前執行計划不是最優的,那么就需要考慮為什么CBO 選擇了錯誤的執行計划。當CBO 選擇錯誤的執行計划,我們需要考慮表的分析是否是最新的,是否對相關的列做了直方圖,是否對分區表做了全局或者分區分析等因素。

關於執行計划參考:

Oracle Explain Plan

 

總之,在處理問題時,我們要把問題掌握在可控的范圍內,不能將問題擴大化,甚至失控。 作為一個DBA,需要的扎實的基本功,還有膽大心細,遇事不慌。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM