基於hints是oracle 最佳化方案

來源:互聯網
上載者:User

hints是oracle提供的一種機制,用來告訴最佳化器按照我們的告訴它的方式產生執行計畫。我們可以用hints來實現:

1. 使用的最佳化器的類型

2.基於代價的最佳化器的最佳化目標,是all_rows還是first_rows。

3. 表的訪問路徑,是全表掃描,還是索引掃描,還是直接利用rowid。

4. 表之間的連線類型

5. 表之間的串連順序

6. 語句的並行程度

除了”RULE”提示外,一旦使用的別的提示,語句就會自動的改為使用CBO最佳化器,此時如果你的資料字典中沒有統計資料,就會使用預設的統計資料。所以建議大家如果使用CBO或HINTS提示,則最好對錶和索引進行週期性分析。

如何使用hints:

Hints只應用在它們所在sql語句塊(statement block,由select、update、delete關鍵字標識)上,對其它SQL語句或語句的其它部分沒有影響。如:對於使用union操作的2個sql語句,如果只在一個sql語句上有hints,則該hints不會影響另一個sql語句。

我們可以使用注釋(comment)來為一個語句添加hints,一個語句塊只能有一個注釋,而且注釋只能放在SELECT, UPDATE, or DELETE關鍵字的後面

使用hints的文法:

{DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */ or {DELETE|INSERT|SELECT|UPDATE} --+ hint [text] [hint[text]]...註解:

1.DELETE、INSERT、SELECT和UPDATE是標識一個語句塊開始的關鍵字,包含提示的注釋只能出現在這些關鍵字的後面,否則提示無效。

2.“+”號表示該注釋是一個hints,該加號必須立即跟在”/*”的後面,中間不能有空格。

3.hint是下面介紹的具體提示之一,如果包含多個提示,則每個提示之間需要用一個或多個空格隔開。

4.text 是其它說明hint的注釋性文本

如果你沒有正確的指定hints,Oracle將忽略該hints,並且不會給出任何錯誤。


使用這一hint,你可以忽略一些關於如詳細的關係依賴圖分析等試算表的編譯時間最佳化規則。其他的一些最佳化,如建立過濾以有選擇性的定位試算表訪問結構並限制修訂規則等,得到了繼續使用。

   由於在規則數非常大的情況下,試算表分析會很長。這一提示可以協助我們減少由此產生的數以百小時計的編譯時間。

例:
    SELECT /*+ SPREAD_MIN_ANALYSIS */ ...

2、spread_no_analysis

   通過這一hint,可以使無試算表分析成為可能。同樣,使用這一hint可以忽略修訂規則和過濾產生。如果存在一試算表分析,編譯時間可以被減少到最低程度。

例:
    SELECT /*+ SPREAD_NO_ANALYSIS */ ...

3、use_nl_with_index

   這項hint使CBO通過嵌套迴圈把特定的表格加入到另一原始行。只有在以下情況中,它才使用特定表格作為內部表格:如果沒有指定標籤,CBO必須可以使用一些標籤,且這些標籤至少有一個作為索引索引值加入判斷;反之,CBO必須能夠使用至少有一個作為索引索引值加入判斷的標籤。

例:
  SELECT /*+ USE_NL_WITH_INDEX (polrecpolrind) */ ...

4、CARDINALITY

  此hint定義了對由查詢或查詢部分返回的基數的評價。注意如果沒有定義表格,基數是由整個查詢所返回的總行數。

例:
  SELECT /*+ CARDINALITY ( [tablespec] card ) */

5、SELECTIVITY

  此hint定義了對查詢或查詢部分選擇性的評價。如果只定義了一個表格,選擇性是在所定義表格裡滿足所有單一表格判斷的行部分。如果定義了一系列表格,選擇性是指在合并以任何順序滿足所有可用判斷的全部表格後,所得結果中的行部分。

例:
   SELECT /*+ SELECTIVITY ( [tablespec] sel ) */

然而,注意如果hints CARDINALITY 和 SELECTIVITY都定義在同樣的一批表格,二者都會被忽略。

6、no_use_nl

  Hint no_use_nl使CBO執行迴圈嵌套,通過把指定表格作為內部表格,把每個指定表格串連到另一原始行。通過這一hint,只有hash join和sort-merge joins會為指定表格所考慮。

例:
   SELECT /*+ NO_USE_NL ( employees ) */ ...

7、no_use_merge

  此hint使CBO通過把指定表格作為內部表格的方式,拒絕sort-merge把每個指定表格加入到另一原始行。

例:
  SELECT /*+ NO_USE_MERGE ( employees dept ) */ ...

8、no_use_hash

  此hint使CBO通過把指定表格作為內部表格的方式,拒絕hash joins把每個指定表格加入到另一原始行。

例:
  SELECT /*+ NO_USE_HASH ( employees dept ) */ ...

9、no_index_ffs

  此hint使CBO拒絕對指定表格的指定標籤進行fast full-index scan。
Syntax: /*+ NO_INDEX_FFS ( tablespecindexspec ) */


在SQL最佳化過程中常見HINT的用法(前10個比較常用, 前3個最常用):

1. /*+ INDEX */ 和 /*+ INDEX(TABLE INDEX1, index2) */ 和 /*+ INDEX(tab1.col1 tab2.col2) */ 和 /*+ NO_INDEX */ 和 /*+ NO_INDEX(TABLE INDEX1, index2) */

表明對錶選擇索引的掃描方法. 第一種不指定索引名是讓oracle對錶中可用索引比較並選擇某個最佳索引; 第二種是指定索引名且可指定多個索引; 第三種是10g開始有的, 指定列名, 且表名可不用別名; 第四種即全表掃描; 第五種表示禁用某個索引, 特別適合於準備刪除某個索引前的評估操作. 如果同時使用了INDEX和NO_INDEX則兩個提示都會被忽略掉.
例如:SELECT /*+ INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';

2. /*+ ORDERED */
FROM子句中預設最後一個表是驅動表,ORDERED將from子句中第一個表作為驅動表. 特別適合於多表串連非常慢時嘗試.
例如:SELECT /*+ ORDERED */ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;

3. /*+ PARALLEL(table1,DEGREE) */ 和 /*+ NO_PARALLEL(table1) */
該提示會將需要執行全表掃描的查詢分成多個部分(並行度)執行, 然後在不同的作業系統進程中處理每個部分. 該提示還可用於DML語句. 如果SQL裡還有排序操作, 進程數會翻倍,此外還有一個一個負責組合這些部分的進程,如下面的例子會產生9個進程. 如果在提示中沒有指定DEGREE, 那麼就會使用建立表時的預設值. 該提示在預設情況下會使用APPEND提示. NO_PARALLEL是禁止並行操作,否則語句會使用由於定義了並行對象而產生的平行處理.
例如:select /*+ PARALLEL(tab_test,4) */ col1, col2 from tab_test order by col2;

4. /*+ FIRST_ROWS */ 和 /*+ FIRST_ROWS(n) */
表示用最快速度獲得第1/n行, 獲得最佳回應時間, 使資源消耗最小化.
在update和delete語句裡會被忽略, 使用分組語句如group by/distinct/intersect/minus/union時也會被忽略.
例如:SELECT /*+ FIRST_ROWS */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

5. /*+ RULE */
表明對語句塊選擇基於規則的最佳化方法.
例如:SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

6. /*+ FULL(TABLE) */
表明對錶選擇全域掃描的方法.
例如:SELECT /*+ FULL(A) */ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT';

7. /*+ LEADING(TABLE) */
類似於ORDERED提示, 將指定的表作為串連次序中的驅動表.

8. /*+ USE_NL(TABLE1,TABLE2) */
將指定表與嵌套的串連的行源進行串連,以最快速度返回第一行再串連,與USE_MERGE剛好相反.
例如:SELECT /*+ ORDERED USE_NL(BSEMPMS) */ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

9. /*+ APPEND */ 和 /*+ NOAPPEND */
直接插入到表的最後,該提示不會檢查當前是否有插入操作所需的塊空間而是直接添加到新塊中, 所以可以提高速度. 當然也會浪費些空間, 因為它不會使用那些做了delete操作的塊空間. NOAPPEND提示則相反,所以會取消PARALLEL提示的預設APPEND提示.
例如:insert /*+ append */ into test1 select * from test4;
insert /*+ parallel(test1) noappend */ into test1 select * from test4;

10. /*+ USE_HASH(TABLE1,table2) */
將指定的表與其它行源通過雜湊串連方式串連起來.為較大的結果集提供最佳回應時間. 類似於在串連表的結果中遍曆每個表上每個結果的嵌套迴圈, 指定的hash表將被放入記憶體, 所以需要有足夠的記憶體(hash_area_size或pga_aggregate_target)才能保證語句正確執行, 否則將在磁碟裡進行.
例如:SELECT /*+ USE_HASH(BSEMPMS,BSDPTMS) */ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

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

11. /*+ USE_MERGE(TABLE) */
將指定的表與其它行源通過合并排序串連方式串連起來.特別適合於那種在多個表大量行上進行集合操作的查詢, 它會將指定表檢索到的的所有行排序後再被合并, 與USE_NL剛好相反.
例如:SELECT /*+ USE_MERGE(BSEMPMS,BSDPTMS) */ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

12. /*+ ALL_ROWS */
表明對語句塊選擇基於開銷的最佳化方法,並獲得最佳輸送量,使資源消耗最小化. 可能會限制某些索引的使用.
例如:SELECT /*+ ALL+_ROWS */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

13. /*+ CLUSTER(TABLE) */
提示明確表明對指定表選擇簇掃描的存取方法. 如果經常訪問串連表但很少修改它, 那就使用叢集提示.
例如:SELECT /*+ CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS WHERE DPT_NO='TEC304' AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

14. /*+ INDEX_ASC(TABLE INDEX1, INDEX2) */
表明對錶選擇索引升序的掃描方法. 從8i開始, 這個提示和INDEX提示功能一樣, 因為預設oracle就是按照升序掃描索引的, 除非未來oracle還推出降序掃描索引.
例如:SELECT /*+ INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';

15. /*+ INDEX_COMBINE(TABLE INDEX1, INDEX2) */
指定多個位元影像索引, 對於B樹索引則使用INDEX這個提示,如果INDEX_COMBINE中沒有提供作為參數的索引,將選擇出位元影像索引的布爾組合方式.
例如:SELECT /*+ INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI) */ * FROM BSEMPMS WHERE SAL<5000000 AND HIREDATE<SYSDATE;

16. /*+ INDEX_JOIN(TABLE INDEX1, INDEX2) */
合并索引, 所有資料都已經包含在這兩個索引裡, 不會再去訪問表, 比使用索引並通過rowid去掃描表要快5倍.
例如:SELECT /*+ INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI) */ SAL,HIREDATE FROM BSEMPMS WHERE SAL<60000;

17. /*+ INDEX_DESC(TABLE INDEX1, INDEX2) */
表明對錶選擇索引降序的掃描方法.
例如:SELECT /*+ INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';

18. /*+ INDEX_FFS(TABLE INDEX_NAME) */
對指定的表執行快速全索引掃描,而不是全表掃描的辦法.要求要檢索的列都在索引裡, 如果表有很多列時特別適用該提示.
例如:SELECT /*+ INDEX_FFS(BSEMPMS IN_EMPNAM) */ * FROM BSEMPMS WHERE DPT_NO='TEC305';

19. /*+ NO_EXPAND */
對於WHERE後面的OR 或者IN-LIST的查詢語句,NO_EXPAND將阻止其基於最佳化器對其進行擴充, 縮短解析時間.
例如:SELECT /*+ NO_EXPAND */ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';

20. /*+ DRIVING_SITE(TABLE) */
強制與ORACLE所選擇的位置不同的表進行查詢執行.特別適用於通過dblink串連的遠端資料表.
例如:SELECT /*+ DRIVING_SITE(DEPT) */ * FROM BSEMPMS,DEPT@BSDPTMS DEPT WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;

21. /*+ CACHE(TABLE) */ 和 /*+ NOCACHE(TABLE) */
當進行全表掃描時,CACHE提示能夠將表全部緩衝到記憶體中,這樣訪問同一個表的使用者可直接在記憶體中尋找資料. 比較適合資料量小但常被訪問的表, 也可以建表時指定cache選項這樣在第一次訪問時就可以對其緩衝. NOCACHE則表示對已經指定了CACHE選項的表不進行緩衝.
例如:SELECT /*+ FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;

22. /*+ PUSH_SUBQ */
當SQL裡用到了子查詢且返回相對少的行時, 該提示可以儘可能早對子查詢進行評估從而改善效能, 不適用於合并串連或帶遠端資料表的串連.
例如:select /*+ PUSH_SUBQ */ emp.empno, emp.ename, itemno from emp, orders where emp.empno = orders.empno and emp.deptno = (select deptno from dept where loc='XXX');
遠端連線其他資料庫,注意判斷資料庫是否啟動,或者是否有需要的表,否則會出錯

23. /*+ INDEX_SS(TABLE INDEX1,INDEX2) */
指示對特定表的索引使用跳躍掃描, 即當複合式索引的第一列不在where子句中時, 讓其使用該索引

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.