oracle之hint概述

不一樣的天空w發表於2017-04-13
oracle之hint概述


1.為什麼引入Hint
Hint是Oracle資料庫中很有特色的一個功能,是很多DBA最佳化中經常採用的一個手段。那為什麼Oracle會考慮引入最佳化器呢?基於代價的最佳化器是很聰明的,在絕大多數情況下它會選擇正確的最佳化器,減輕DBA的負擔。

但有時它也聰明反被聰明誤,選擇了很差的執行計劃,使某個語句的執行變得奇慢無比。此時就需要DBA進行人為的干預,告訴最佳化器使用指定的存取路徑或連線型別生成執行計劃,從而使語句高效地執行。Hint就是Oracle提供的一種機制,用來告訴最佳化器按照告訴它的方式生成執行計劃。

Hint 是Oracle 提供的一種SQL語法,它允許使用者在SQL語句中插入相關的語法,從而影響SQL的執行方式。

因為Hint的特殊作用,所以對於開發人員不應該在程式碼中使用它,Hint 更像是Oracle提供給DBA用來分析問題的工具 。在SQL程式碼中使用Hint,可能導致非常嚴重的後果,因為資料庫的資料是變化的,在某一時刻使用這個執行計劃是最優的,在另一個時刻,卻可能很差,這也是CBO 取代RBO的原因之一,規則是死的,而資料是時刻變化的,為了獲得最正確的執行計劃,只有知道表中資料的實際情況,透過計算各種執行計劃的成本,則其最優,才是最科學的,這也是CBO的工作機制。 在SQL程式碼中加入Hint,特別是效能相關的Hint是很危險的做法。

Hint是Oracle提供的一種SQL語法,它允許使用者在SQL語句中插入相關的語法,從而影響SQL的執行方式。

在使用Hint的時候需要注意一點的是,並非在任何時候Hint都起作用,原因是如果CBO認為使用Hint會導致錯誤的結果時,Hint將被忽略。

2.不要過分依賴Hint
當遇到SQL執行計劃不好的情況,應優先考慮統計資訊等問題,而不是直接加Hint了事。如果統計資訊無誤,應該考慮物理結構是否合理,即沒有合適的索引。只有在最後仍然不能SQL按最佳化的執行計劃執行時,才考慮Hint。

畢竟使用Hint,需要應用系統修改程式碼,Hint只能解決一條SQL的問題,並且由於資料分佈的變化或其他原因(如索引更名)等,會導致SQL再次出現效能問題。


3.Hint的弊端
    Hint是比較"暴力"的一種解決方式,不是很優雅。需要開發人員手工修改程式碼。

    Hint不會去適應新的變化。比如資料結構、資料規模發生了重大變化,但使用Hint的語句是感知變化併產生更優的執行計劃。

    Hint隨著資料庫版本的變化,可能會有一些差異、甚至廢棄的情況。此時,語句本身是無感知的,必須人工測試並修正。


4.Hint與註釋關係
提示是Oracle為了不破壞和其他資料庫引擎之間對SQL語句的相容性而提供的一種擴充套件功能。Oracle決定把提示作為一種特殊的註釋來新增。它的特殊性表現在提示必須緊跟著DELETE、INSERT、UPDATE或MERGE關鍵字。

換句話說,提示不能像普通註釋那樣在SQL語句中隨處新增。且在註釋分隔符之後的第一個字元必須是加號。在後面的用法部分,會詳細說明。

5.Hint功能
Hint提供的功能非常豐富,可以很靈活地調整語句的執行過程。透過Hint,我們可以調整:

     最佳化器型別

    最佳化器最佳化目標

    資料讀取方式(訪問路徑)

    查詢轉換型別

    表間關聯的順序

    表間關聯的型別

    並行特性

    其他特性

6.HINT應用範圍
  dml語句

  查詢語句

7.語法

  {DELETE|INSERT|SELECT|UPDATE} /*+ hint [text] [hint[text]]... */

  or

  {DELETE|INSERT|SELECT|UPDATE} --+ hint [text] [hint[text]]...

  如果語(句)法不對,則ORACLE會自動忽略所寫的HINT,不報錯
 
 
7.1)關鍵字說明
    DELETE、INSERT、SELECT和UPDATE是標識一個語句塊開始的關鍵字,包含提示的註釋只能出現在這些關鍵字的後面,否則提示無效。

    "+"號表示該註釋是一個提示,該加號必須立即跟在"/*"的後面,中間不能有空格。

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

    text是其它說明hint的註釋性文字

7.2)提示中的錯誤
提示中的語法錯誤不會報錯,如果解析器不能解析它,就會把它看做一個普通註釋處理。這也是容易造成困惑的一點,使用的Hint到底是否起效?可以採用一些手段,檢查提示的有效性。需要注意的是,那些語法正確但引用物件錯誤的提示是不會被報告的。

    explain plan + dbms_xplan: 使用dbms_xplan輸出中的note選項。
 
    10132事件:在10g中,這個事件產生的輸出文件的末尾有一部分內容專門講提示。透過它可以檢查兩個方面:一是每個用到的提示都會被列出來。如果漏掉了哪個,就說明這個提示沒有被識別;二是檢查是否有一些資訊指明瞭出現提示錯誤(如果出錯,err值將大於0)。

7.3)提示中的物件
SELECT /*+ INDEX(table_name index_name) */ ...

    table_name是必須要寫的,且如果在查詢中使用了表的別名,在hint也要用表的別名來代替表名。

    index_name可以不必寫,Oracle會根據統計值選一個索引。

    如果索引名或表名寫錯了,那這個hint就會被忽略。

    如果指定物件是檢視,需要按此方法指定。/*+hint view.table ...*/,其中table是view中的表。

    一個很常見的錯誤時,在使用提示的時候最易犯的錯誤是與表的別名有關。正確的規則是,當在提示中使用表時,只要表有別名就應該使用別名而不是表名。

8.Hint分類

8.1和最佳化器相關的

當對最佳化器為某個語句所制定的基本執行計劃不滿意時,最好的辦法就是透過提示來轉換最佳化器的模式,並觀察其轉換後的結果,看是否已經達到期望程度。如果只透過轉換最佳化器的模式就可以獲得非常好的執行計劃,則就沒有必要額外使用更為複雜的提示了。

     OPT_PARAM:這個提示的作用就是使我們在某條語句中指定某個系統引數值。

     ALL_ROWS :實現查詢語句整體最最佳化而引導最佳化器制定最少成本的執行計劃。這個提示會使最佳化器選擇一條可最快檢索所有查詢行的路徑,而代價就是在檢索一行資料時,速度很慢。

    FIRST_ROWS :為獲得最佳響應時間而引導最佳化器制定最少成本的執行計劃。這個提示會使最佳化器選擇可最快檢索出查詢的第一行(或指定行)資料的路徑,而代價就是檢索很多行時速度就會很慢。利用FIRST_ROWS來最佳化的行數,預設值為1,這個值介於10到1000之間,這個使用FIRST_ROWS(n)的新方法是完全基於代價的方法。它對n很敏感,如果n值很小,CBO就會生成包含巢狀迴圈以及索引查詢的計劃;如果n很大,CBO會生成由雜湊連線和全表掃描組成的計劃(類似ALL_ROWS)。

    CHOOSE:依據SQL中所使用到的表的統計資訊存在與否,來決定使用RBO還是CBO。在CHOOSE模式下,如果能夠參考表的統計資訊,則將按照ALL_ROWS方式執行。除非在查詢中的所有表都沒有經過分析,否則choose提示會對整個查詢使用基於代價的最佳化。如果在多表連線中有一個表經過分析過,那麼就會對整個查詢進行基於代價的最佳化。

     RULE:使用基於規則的最佳化器來實現最最佳化執行,即引導最佳化器根據優先順序規則來決定查詢條件中所使用到的索引或運算子的執行順序來制定執行計劃。這個提示強制oracle優先使用預定義的一組規則,而不是對資料進行統計;同時該提示還會使這個語句避免使用其他提示,除了DRIVING_SITE和ORDERED(不管是否進行基於規則的最佳化,這兩個提示都可使用)。


8.2和訪問路徑相關的

    FULL:告訴最佳化器透過全表掃描方式訪問資料。這個提示只對所指定的表進行全表掃描,而不是查詢中的所有表。FULL提示可以改善效能。這主要是因為它改變了查詢中的驅動表,而不是因為全表掃描。在使用其他某些提示時,也必須使用FULL提示。只有訪問整個表時,才可利用CACHE提示將表進行快取。並行組中的某些提示也必須使用全表掃描。

    CLUSTER:引導最佳化器透過掃描聚簇索引來從索引表中讀取資料。

    HASH:引導最佳化器按照雜湊掃描的方式從表中讀取資料。

   INDEX:告訴最佳化器對指定表透過索引的方式訪問資料。當訪問資料會導致結果集不完整時,最佳化器將忽略這個Hint。

   NO_INDEX:告訴最佳化器對指定表不允許使用索引。這個提示會禁止最佳化器使用指定索引。可以在刪除不必要的索引之前在許多查詢中禁止索引。如果使用了NO_INDEX,但是沒有指定任何索引,則會執行全表掃描。如果對某個索引同時使用了NO_INDEX和會之產生衝突的提示(如INDEX),這時兩個提示都會被忽略掉。

   INDEX_ASC:利用索引從表中讀取資料時,引導最佳化器對提示中所指定索引的索引列值按照升序使用範圍掃描。

   INDEX_COMBINE:告訴最佳化器強制選擇點陣圖索引。這個提示會使最佳化器合併表上的多個點陣圖索引,而不是選擇其中最好的索引(這是INDEX提示的用途)。還可以使用index_combine指定單個索引(對於指定點陣圖索引,該提示優先於INDEX提示)。對於B樹索引,可以使用AND_EQUAL提示而不是這個提示。

   INDEX_JOIN:索引關聯,當謂詞中引用的列上都有索引的時候,可以透過索引關聯的方式來訪問資料。這個提示可以將同一個表的各個不同索引進行合併,這樣就只需要訪問這些索引就可以了,節省了回表查詢的時間。但只能在基於代價的最佳化器中使用該提示。這個提示不僅允許只訪問表上的索引,這樣可以掃描更少的程式碼塊,並且它比使用索引並透過rowid掃描整個錶快5倍。

   INDEX_DESC:利用索引從表中讀取資料時,引導最佳化器對提示中所指定索引的索引列值按照降序使用範圍掃描。

   INDEX_FFS:告訴最佳化器以INDEX FFS(index fast full scan)的方式訪問資料。INDEX_FFS提示會執行一次索引的快速全域性掃描。這個提示只訪問索引,而不是對應的表。只有查詢需要檢索的資訊都在索引上時,才使用這個提示。特別在表有很多列時,使用該提示可以極大地改善效能。

   INDEX_SS:強制使用index skip scan的方式訪問索引。當在一個聯合索引中,某些謂詞條件並不在聯合索引的第一列時(或者謂詞並不在聯合索引的第一列時),可以透過index skip scan來訪問索引獲得資料。當聯合索引第一列的唯一值很少時,使用這種方式比全表掃描的方式效率要高。


8.3和查詢轉換相關的

    USE_CONCAT:將含有多個OR或者IN運算子所連線起來的查詢語句分解為多個單一查詢語句,併為每個單一查詢語句選擇最最佳化查詢路徑,然後再將這些最最佳化查詢路徑結合在一起,以實現整體查詢語句的最最佳化目的。只有在驅動查詢條件中包含OR的時候,才可以使用該提示。

    NO_EXPAND:引導最佳化器不要為使用OR運算子號(或IN運算子)的條件制定相互結合的執行計劃。正好和USE_CONCAT相反。

    REWRITE:當表連線的物件是資料量比較大的表或者需要獲得使用統計函式處理過的結果時,為了提高執行速度可預先建立物化檢視。當使用者要求查詢某個查詢語句時,最佳化器會在從表中和從物化檢視中讀取資料的兩種方法中選擇一個更有效的方法來讀取資料。該執行方法稱之為查詢重寫。使用REWRITE提示引導最佳化器按照該方式執行。

    MERGE:為了能以最優方式從檢視或者巢狀檢視中讀取資料,透過變換查詢語句來直接讀取檢視使用的基表資料,該過程被稱之為檢視合併。不同的情況其具體使用型別也有所不同。該提示主要在檢視未發生合併時被使用。尤其是對比較複雜的檢視或者巢狀檢視(比如使用了GROUP BY或DISTINC的檢視)使用該提示,有時會取得非常好的效果。

    UNNEST:提示最佳化器將子查詢轉換為連線的方式。也就是引導最佳化器合併子查詢和主查詢並且將其向連線型別轉換。

    NO_UNNEST:引導最佳化器讓子查詢能夠獨立地執行完畢之後再跟外圍的查詢做FILTER。

    PUSH_PRED:使用該提示可以將檢視或巢狀檢視以外的查詢條件推入到檢視之內。

    NO_PUSH_PRED:使用該提示確保檢視或巢狀檢視以外的查詢條件不被推入到檢視內部。

    PUSH_SUBQ:使用該提示引導最佳化器為不能合併的子查詢制定執行計劃。不能合併的子查詢被優先執行之後,該子查詢的執行結果將扮演縮減主查詢資料查詢範圍的提供者角色。通常在無法執行子查詢合併的情況下,子查詢扮演的都是檢驗者角色,所以子查詢一般被放在最後執行。在無法被合併的子查詢擁有較少的結果行,或者該子查詢可以縮減主查詢查詢範圍的情況下,可以使用該提示引導最佳化器最大程度地將該子查詢放在前面執行,以提高執行速度。但如果子查詢執行的是遠端表或者排序合併連線的一部分連線結果,則該提示將不起任何作用。

    NO_PUSH_SUBQ:使用該提示將引導最佳化器將不能實現合併的子查詢放在最後執行。在子查詢無法縮減主查詢的查詢範圍,或者執行子查詢開銷較大的情況下,將這樣的子查詢放在最後執行可以在某種程度上提高整體的執行效率。也就是說,儘可能地使用其他查詢條件最大程度地縮減查詢範圍之後,再執行子查詢。


8.4和表連線順序相關的

這些提示可以調整表連線的順序。調整表連線的順序並不是只能使用這些提示,在巢狀迴圈連線方式中也可以讓提示來引導最佳化器使用由驅動查詢條件所建立的索引。然而,該方法只有在使用的索引和表連線順序同時被調整的情況下才比較有效。一般而言,這些提示主要在執行多表連線和表之間的連線順序比較混亂的情況下才使用,也在排序合併連線或雜湊連線方式下,為引導最佳化器優先執行資料量比較少得表時使用。

    LEADING:在一個多表關聯的查詢中,這個Hint指定由哪個表作為驅動表,即告訴最佳化器首先要訪問那個表上的資料。引導最佳化器使用LEADING指定的表作為表連線順序中的第一個表。該提示既與FROM中所描述的表的順序無關,也與作為調整表連線順序的ORDERED提示不同,並且在使用該提示時並不需要調整FROM中所描述的表的順序。當該提示與ORDERED提示同時使用時,該提示被忽略。

這個提示類似ORDERED提示,它允許指定驅動查詢的表,然後由最佳化器來判斷下一個要訪問的表。如果使用這個提示指定多張表,那麼就可以忽略這個提示。

    ORDERED:引導最佳化器按照FROM中所描述的表的順序執行連線。如果和LEADING提示被一起使用,則LEADING提示將被忽略。由於ORDERED只能調整表連線的順序並不能改變表連線的方式,所以為了改變表的連線方式,經常將USE_NL、USE_MERGE提示與ORDERED提示放在一起使用。

 
8.5和表連線操作相關的

    USE_NL:使用該提示引導最佳化器按照巢狀迴圈連線方式執行表連線。它只是指出表連線的方式,對於表連線順序不會有任何影響。

   USE_MERGE:引導最佳化器按照排序合併連線方式執行連線。在有必要的情況下,推薦將該提示與ORDERED提示一起使用。提示通常用於獲得查詢的最佳吞吐量。假設將兩個表連線在一起,從每個表返回的行集將被排序,然後再被合併(也就是合併排序),從而組成最終的結果集。由於每個行先被排序之後才進行合併,所以在給定查詢中檢索所有行時,速度將會最快。如果需要以最快速度返回第一行,就應該使用USE_NL提示。

    USE_HASH:該提示引導最佳化器按照雜湊連線方式執行連線。在執行雜湊連線時,如果由於某一邊的表比較小,從而可以在記憶體中實現雜湊連線,那麼就能夠獲得非常好的執行速度。由於在大部分情況下最佳化器會透過對統計資訊的分析來決定Build Input和Prove Input,所以建議不要使用ORDERED提示隨意改變表的連線順序。但是當最佳化器沒能做出正確判斷時,或者像從巢狀檢視中所獲得的結果集合那樣不具備統計資訊時,可以使用該提示。


8.6和並行相關的

    PARALLEL:指定SQL執行的並行度,這個值將會覆蓋表自身設定的並行度。如果這個值為default,CBO使用系統引數。從表中讀取大量資料和執行DML操作時使用該提示來指定SQL的並行操作。一般情況下需要在該提示中指定將要使用的並行執行緒個數。如果在該提示中沒有指定並行度的個數,則最佳化器將使用PARALLEL_THREADS_PER_CPU引數所指定的值進行自動計算。如果在定義表時指定了PARALLEL,那麼在能夠使用並行操作的情況下,即使沒有使用該提示,最佳化器也會按照指定的並行級別選擇並行操作。但是如果想在DELETE、INSERT、UPDATE、MERGE等DML操作中使用並行操作,則必須要在會話中設定ALTER SESSION ENABLE PARALLEL DML。在某個會話中所設定的並行級別也可以被引用在內部的GROUP BY或者排序操作中。在並行操作中如果出現了某個限制要素,則該提示將被忽略。

    NOPARALLEL/NO_PARALLEL:在SQL語句禁止使用並行。在有些版本中用NO_PARALLEL提示來代替NOPARALLEL提示。

    PQ_DISTRIBUTE:為了提高並行連線的執行速度,使用該提示來定義使用何種方法在主從程式之間(例如生產者程式和消費者程式)分配各連線表的資料行。

    PARALLEL_INDEX:為了按照並行操作的方式對分割槽索引進行索引範圍掃描而使用該提示,並且可以指定程式的個數。


8.7其他相關的

    APPEND:讓資料庫以直接載入的方式(direct load)將資料載入入庫。這個提示不會檢查當前是否有插入所需要的塊空間,相反它會直接將資料新增到新塊中。這樣會浪費空間,但可以提高插入的效能。需要注意的是,資料將被儲存在HWM之上的位置。

    APPEND_VALUES:在11.2中,Oracle新增了APPEND_VALUES提示,使得INSERT INTO VALUES語句也可以使用直接路徑插入。

    CACHE:在全表掃描之後,資料塊將留在LRU列表的最活躍端。如果設定表的CACHE屬性,它的作用和HINT一樣。這個提示會將全表掃描全部快取到記憶體中。如果表很大,會佔用大量記憶體。因此適用於使用者經常訪問的較小的表。

    NOCACHE:引導最佳化器將透過全表掃描方式獲取的資料塊快取在LRU列表的最後位置,這樣可以讓資料庫例項快取中的這些資料塊被優先清除。這是最佳化器在Buffer Cache中管理資料塊的預設方法(僅針對全表掃描)。

    QB_NAME:使用該提示為查詢語句塊命名,在其他查詢語句塊可以直接使用該查詢語句塊的名稱。

    DRIVING_SITE:這個提示在分散式資料庫操作中有用。指定表是處理連線所在的位置。可以限制透過網路處理的資訊量。此外,還可以建立遠端表的本地檢視來限制從遠端站點檢索的行。本地檢視應該有where子句,從而檢視可以在將行傳送回本地資料庫之前限制從遠端資料庫返回的行。

    DYNAMIC_SAMPLING:提示SQL執行時動態取樣的級別。這個級別為0~10,它將覆蓋系統預設的動態取樣級別。等級越高,所獲得統計資訊的準確率越高。該提示的功能就是為了確保將動態取樣原理應用在單個SQL中。

    AND_EQUAL:這個提示會使最佳化器合併表上的多個索引,而不是選擇其中最好的索引(這是INDEX提示的用途)。這個提示與前面的INDEX_JOIN提示有區別,以此指定的合併索引隨後需訪問表,而INDEX_JOIN提示則只需訪問索引。如果發現需經常用到這個提示,可能需要刪除這些單個索引而改用一個組合索引。需要查詢條件裡面包括所有索引列,然後取得每個索引中得到的rowid列表。然後對這些物件做merge join,過濾出相同的rowid後再去表中獲取資料或者直接從索引中獲得資料。在10g中,and_equal已經廢棄了,只能透過hint才能生效。

    CARDINALITY:向最佳化器提供對某個查詢語句的整體或部分的預測基數值,並透過參考該基數值來為查詢語句制定執行計劃。如果在該提示中沒有指定表的名稱,則該基數值將被視為從該查詢語句所獲得的最終結果行數。

=========================補充===================
1. /*+ALL_ROWS*/

  表明對語句塊選擇基於開銷的最佳化方法,並獲得最佳吞吐量,使資源消耗最小化.

  例如:

  SELECT /*+ALL_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

  2. /*+FIRST_ROWS*/

  表明對語句塊選擇基於開銷的最佳化方法,並獲得最佳響應時間,使資源消耗最小化.

  例如:

  SELECT /*+FIRST_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

  3. /*+CHOOSE*/

  表明如果資料字典中有訪問表的統計資訊,將基於開銷的最佳化方法,並獲得最佳的吞吐量;

  表明如果資料字典中沒有訪問表的統計資訊,將基於規則開銷的最佳化方法;

  例如:

  SELECT /*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

  4. /*+RULE*/

  表明對語句塊選擇基於規則的最佳化方法.

  例如:

  SELECT /*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';

  5. /*+FULL(TABLE)*/

  表明對錶選擇全域性掃描的方法.

  例如:

  SELECT /*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT';

  6. /*+ROWID(TABLE)*/

  提示明確表明對指定表根據 ROWID進行訪問.

  例如:

  SELECT /*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID>='AAAAAAAAAAAAAA'

  AND EMP_NO='SCOTT';

  7. /*+CLUSTER(TABLE)*/

  提示明確表明對指定表選擇簇掃描的訪問方法,它只對簇物件有效.

  例如:

  SELECT /*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS

  WHERE DPT_NO='TEC304' AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

  8. /*+INDEX(TABLE INDEX_NAME)*/

  表明對錶選擇索引的掃描方法.

  例如:

  SELECT /*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';

  9. /*+INDEX_ASC(TABLE INDEX_NAME)*/

  表明對錶選擇索引升序的掃描方法.

  例如:

  SELECT /*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';

  10. /*+INDEX_COMBINE*/

  為指定表選擇點陣圖訪問路經,如果INDEX_COMBINE中沒有提供作為引數的索引,將選擇出點陣圖索引的布林組合方式.

  例如:

  SELECT /*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMS

  WHERE SAL<5000000 AND HIREDATE

  11. /*+INDEX_JOIN(TABLE INDEX_NAME)*/

  提示明確命令最佳化器使用索引作為訪問路徑.

  例如:

  SELECT /*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATE

  FROM BSEMPMS WHERE SAL<60000;

  12. /*+INDEX_DESC(TABLE INDEX_NAME)*/

  表明對錶選擇索引降序的掃描方法.

  例如:

  SELECT /*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';

  13. /*+INDEX_FFS(TABLE INDEX_NAME)*/

  對指定的表執行快速全索引掃描,而不是全表掃描的辦法.

  例如:

  SELECT /*+INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';

  14. /*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/

  提示明確進行執行規劃的選擇,將幾個單列索引的掃描合起來.

  例如:

  SELECT /*+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)*/ * FROM BSEMPMS WHERE EMP_NO='SCOTT' AND DPT_NO='TDC306';

  15. /*+USE_CONCAT*/

  對查詢中的WHERE後面的OR條件進行轉換為UNION ALL的組合查詢.
  例如:

  SELECT /*+USE_CONCAT*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';

  16. /*+NO_EXPAND*/

  對於WHERE後面的OR 或者IN-LIST的查詢語句,NO_EXPAND將阻止其基於最佳化器對其進行擴充套件.

  例如:

  SELECT /*+NO_EXPAND*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';

  17. /*+NOWRITE*/

  禁止對查詢塊的查詢重寫操作.

  18. /*+REWRITE*/

  可以將檢視作為引數.

  19. /*+MERGE(TABLE)*/

  能夠對檢視的各個查詢進行相應的合併.

  例如:

  SELECT /*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO

  ,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO

  AND A.SAL>V.AVG_SAL;

  20. /*+NO_MERGE(TABLE)*/

  對於有可合併的檢視不再合併.

  例如:

  SELECT /*+NO_MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELECT DPT_NO,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO AND A.SAL>V.AVG_SAL;

  21. /*+ORDERED*/

  根據表出現在FROM中的順序,ORDERED使ORACLE依此順序對其連線.

  例如:

  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;

  22. /*+USE_NL(TABLE)*/

  將指定表與巢狀的連線的行源進行連線,並把指定表作為內部表.

  例如:

  SELECT /*+ORDERED USE_NL(BSEMPMS)*/ BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

  23. /*+USE_MERGE(TABLE)*/

  將指定的表與其他行源透過合併排序連線方式連線起來.

  例如:

  SELECT /*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

  24. /*+USE_HASH(TABLE)*/

  將指定的表與其他行源透過雜湊連線方式連線起來.

  例如:

  SELECT /*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;

  25. /*+DRIVING_SITE(TABLE)*/

  強制與ORACLE所選擇的位置不同的表進行查詢執行.

  例如:

  SELECT /*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;

  26. /*+LEADING(TABLE)*/

  將指定的表作為連線次序中的首表.

  27. /*+CACHE(TABLE)*/

  當進行全表掃描時,CACHE提示能夠將表的檢索塊放置在緩衝區快取中最近最少列表LRU的最近使用端

  例如:

  SELECT /*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;

  28. /*+NOCACHE(TABLE)*/

  當進行全表掃描時,CACHE提示能夠將表的檢索塊放置在緩衝區快取中最近最少列表LRU的最近使用端

  例如:

  SELECT /*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;

  29. /*+APPEND*/

  直接插入到表的最後,可以提高速度.

  insert /*+append*/ into test1 select * from test4 ;

  30. /*+NOAPPEND*/

  透過在插入語句生存期內停止並行模式來啟動常規插入.

  insert /*+noappend*/ into test1 select * from test4 ;

  31. NO_INDEX: 指定不使用哪些索引

  /*+ NO_INDEX ( table [index [index]...] ) */

  select /*+ no_index(emp ind_emp_sal ind_emp_deptno)*/ * from emp where deptno=200 and sal>300;

  32. parallel

  select /*+ parallel(emp,4)*/ * from emp where deptno=200 and sal>300;

  另:每個SELECT/INSERT/UPDATE/DELETE命令後只能有一個/*+ */,但提示內容可以有多個,可以用逗號分開,空格也可以。

  如:/*+ ordered index() use_nl() */

---------
類似如下的一條語句:insert into xxxx select /*+parallel(a) */ * from xxx a;資料量大約在75G左右,這位兄弟從上午跑到下午還沒跑完,過來問我咋回事,說平常2hrs能跑完的東西跑了好幾個小時還撒動靜。檢視系統效能也比較 正常,cpu,io都不繁忙,平均READ速度在80M/s左右(勉強湊合),但平均寫速度只有10M不到。等待事件裡面大量的‘ ‘PX Deq Credit: send blkd’,這裡能看出並行出了問題,從而最後得知是並行用法有問題,修改之後20分鐘完成了該操作。正確的做法應該是:
alter session enable dml parallel;

insert /*+parallel(xxxx,4) */ into xxxx select /*+parallel(a) */ * from xxx a;

因為oracle預設並不會開啟PDML,對DML語句必須手工啟用。 另外不得不說的是,並行不是一個可擴充套件的特性,只有在資料倉儲或作為DBA等少數人的工具在批次資料操作時利於充分利用資源,而在OLTP環境下使用並行 需要非常謹慎。事實上PDML還是有比較多的限制的,例如不支援觸發器,引用約束,高階複製和分散式事務等特性,同時也會帶來額外的空間佔用,PDDL同 樣是如此。有關Parallel excution可參考官方文件,在Thomas Kyte的新書《Expert Oracle Database architecture》也有精闢的講述。
---------
select count(*)
  From wid_serv_prod_mon_1100 a
 where a.acct_month = 201010
   and a.partition_id = 10
   and serv_state not in ('2HB', '2HL', '2HJ', '2HP', '2HF')
   and online_flag in (0)
   and incr_product_id in (2000020)
   and product_id in (2020966, 2020972, 2100297, 2021116)
   and billing_mode_id = 1
   and exp_date > to_date('201010', 'yyyymm')
   and not exists (select /*+no_index (b IDX_W_CDR_MON_SERV_ID_1100)*/
         1
          from wid_cdr_mon_1100 b
         where b.acct_month = 201010
           and b.ANA_EVENT_TYPE_4 in
               ('10201010201', '10202010201', '10203010201', '10203010202', '10203030201', '10203030202', '10204010201', '10204010202', '10204030201')
           and a.serv_id = b.serv_id)

===========常見hint補充=============
與最佳化器模式相關的hint
    1.1 /*+ all_rows */ 讓最佳化器啟動CBO  
    1.2 /*+ first_rows(n)*/最佳化器啟動CBO,選擇會快返回前n行資料的執行計劃。與first_rows_n不同,first_rows_n n只能為1,10,100,1000.  
    1.3 /*+ rule */ 啟動RBO,與其他hint連用,其他hint一般會失效。  


與表及索引訪問相關的hint
    2.1 full(xxx) 全表掃描  
    2.2 index(目標表 目標索引1 目標索引2)   
    2.3 no_index(目標表 目標索引1 目標索引2)   
    2.4 index_desc(目標表 目標索引1 目標索引2) 讓最佳化器對目標索引執行降序掃描,如目標索引是降序,則hint則以升序掃描目標索引。  
    2.5 index_ffs(目標表 目標索引1 目標索引2)  索引快速全掃描   


與表連線順序相關的hint
    3.1 ordered 讓最佳化器在執行多表連線時,按照他們在sql中where條件出現順序進行連線。查詢轉換可能會導致這個hint失效。  
    3.2 leading(表1 表2) 讓最佳化器將我們執行多個表的連線結果作為目標sql表連線過程中的結果集,並將hint中自左到右的第一個表,作為表連線的驅動表。  


與表連線方法相關的hint
    4.1 use_merge(表1 表2) 讓最佳化器將我們指定的多個表作為被驅動表與其他表或結果集做排序合併連線。  
    4.2 no_use_merge(表1 表2)  
    4.3 use_nl(表1 表2) 讓最佳化器將我們指定的多個表作為被驅動表與其他表或結果集做巢狀迴圈連線。經常與leading合用。  
    /*+use_nl(s,X) leading X */  
    4.4 no_use_merge(表1 表2)  
    4.5 use_hash(表1 表2) 讓最佳化器將我們指定的多個表作為被驅動表與其他表或結果集做雜湊連線。經常與leading合用。  
    4.6 no_use_merge(表1 表2)  
    4.7 merge_aj 針對子查詢的hint,讓最佳化器對目標表執行排序合併反連線。  
    4.8 nl_aj 針對子查詢的hint,讓最佳化器對目標表執行巢狀迴圈反連線。  
    4.9 hash_aj 針對子查詢的hint,讓最佳化器對目標表執行雜湊反連線。  
    4.10 merge_sj 針對子查詢的hint,讓最佳化器對目標表執行排序合併半連線。  
    4.11 nl_sj 針對子查詢的hint,讓最佳化器對目標表執行巢狀迴圈半連線。  
    4.12 hash_sj 針對子查詢的hint,讓最佳化器對目標表執行雜湊半連線  


與查詢轉換相關的hint
    5.1 use_concat 是針對目標sql的hint,讓最佳化器對目標sql使用in_list擴充套件或or_list擴充套件。  
    5.2 no_expand 是use_concat反義hint,不讓最佳化器對目標sql使用in_list擴充套件或or_list擴充套件。  
    5.3 merge 是針對單個目標檢視的hint,讓最佳化器對目標檢視執行檢視合併(view merging)  
    5.4 no_merge 是針對merge的反義hint,不讓最佳化器對目標檢視執行檢視合併(view merging)  
    5.5 unnest 是針對子查詢的hint,讓最佳化器對目標sql中的子查詢展開(subquery unnesting)  
    5.6 no_unnest 是針對unnest反義的hint,不讓最佳化器對目標sql中的子查詢展開(subquery unnesting)  
    5.7 expand_table(表) 讓最佳化器在不考慮成本的情況下,對錶進行表擴充套件  
    5.8 no_expand_table(表) expand_table(表)的反義hint,不對錶進行表擴充套件  


與並行有關的hint
    6.1 parallel 並行  
    6.2 no_parallel 針對整個目標sql的hint  
    6.3 parallel_index(表 index-1 index-2 ... index-n n n n )  
    6.4 no_parallel_index(表 index-1 index-2 ... index-n)  


其他常見hint
    7.1 driving_site 讓最佳化器在我們指定目標表所在的節點上執行目標sql。只適用於帶dblink的分散式查詢語句。  
    7.2 append 讓最佳化器執行帶子查詢的insert時,繞開buffer cache,使用直接路徑插入。  
    7.3 append_values 讓最佳化器執行帶values的insert時,繞開buffer cache,使用直接路徑插入。(11R2)  
    7.4 push_pred 針對目標檢視的hint,讓最佳化器對目標檢視執行連線謂詞推入。  
    7.5 no_push_pred 針對目標檢視的hint,不讓最佳化器對目標檢視執行連線謂詞推入。  
    7.6 push_subq 針對子查詢的hint,讓最佳化器儘早執行目標sql中不能做子查詢展開的子查詢。  
    7.7 no_push_subq 針對子查詢的hint,讓最佳化器最後執行目標sql中不能做子查詢展開的子查詢。  
    7.8 opt_param 針對目標sql的hint,用來修改針對目標sql比系統級,session級更細顆粒的更改。  
    7.9 optimizer_features_enable('最佳化器版本號') 更改最佳化器版本  
    7.10 qb_name 對一個查詢塊指定自定義的名稱。  
    7.11 cardinality 針對單個目標表的hint,用來設定對目標表執行掃描操作後的cardinality的值。(對唯一索引掃描無效)  
    7.12 swap_join_inputs 針對hash連線的hint,讓最佳化器交換原hash連線的驅動表和被驅動表順序。 




來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31397003/viewspace-2137150/,如需轉載,請註明出處,否則將追究法律責任。

相關文章