Hint是Oracle數據庫中頗有特點的一個功能,是不少DBA優化中常常採用的一個手段。那爲何Oracle會考慮引入優化器呢?基於代價的優化器是很聰明的,在絕大多數狀況下它會選擇正確的優化器,減輕DBA的負擔。數據庫
但有時它也聰明反被聰明誤,選擇了不好的執行計劃,使某個語句的執行變得奇慢無比。此時就須要DBA進行人爲的干預,告訴優化器使用指定的存取路徑或鏈接類型生成執行計劃,從而使語句高效地運行。Hint就是Oracle提供的一種機制,用來告訴優化器按照告訴它的方式生成執行計劃。緩存
當遇到SQL執行計劃很差的狀況,應優先考慮統計信息等問題,而不是直接加Hint了事。若是統計信息無誤,應該考慮物理結構是否合理,即沒有合適的索引。只有在最後仍然不能SQL按優化的執行計劃執行時,才考慮Hint。網絡
畢竟使用Hint,須要應用系統修改代碼,Hint只能解決一條SQL的問題,而且因爲數據分佈的變化或其餘緣由(如索引改名)等,會致使SQL再次出現性能問題。數據結構
提示是Oracle爲了避免破壞和其餘數據庫引擎之間對SQL語句的兼容性而提供的一種擴展功能。Oracle決定把提示做爲一種特殊的註釋來添加。它的特殊性表如今提示必須緊跟着DELETE、INSERT、UPDATE或MERGE關鍵字。oracle
換句話說,提示不能像普通註釋那樣在SQL語句中隨處添加。且在註釋分隔符以後的第一個字符必須是加號。在後面的用法部分,會詳細說明。分佈式
Hint提供的功能很是豐富,能夠很靈活地調整語句的執行過程。經過Hint,咱們能夠調整:函數
提示中的語法錯誤不會報錯,若是解析器不能解析它,就會把它看作一個普通註釋處理。這也是容易形成困惑的一點,使用的Hint究竟是否起效?能夠採用一些手段,檢查提示的有效性。須要注意的是,那些語法正確但引用對象錯誤的提示是不會被報告的。性能
使用dbms_xplan輸出中的note選項。測試
在10g中,這個事件產生的輸出文檔的末尾有一部份內容專門講提示。經過它能夠檢查兩個方面:一是每一個用到的提示都會被列出來。若是漏掉了哪一個,就說明這個提示沒有被識別;二是檢查是否有一些信息指明瞭出現提示錯誤(若是出錯,err值將大於0)。優化
SELECT /+ INDEX(table_name index_name) / ...
若是指定對象是視圖,須要按此方法指定。/*+hint view.table ...*/,其中table是view中的表。
一個很常見的錯誤時,在使用提示的時候最易犯的錯誤是與表的別名有關。正確的規則是,當在提示中使用表時,只要表有別名就應該使用別名而不是表名。
初始化參數提示對整個SQL語句起做用,其餘的提示僅僅對查詢塊起做用。僅僅對單個查詢塊起做用的提示,必須在它控制的查詢塊內指定。
可使用點號引用包含在其餘查詢塊(假設這些塊已命名)中的對象。全局提示的語法能夠支持兩層以上的引用,對象間必須用點號分隔。
既然where子句中的子查詢是沒有命名的,它們的對象就不能被全局提示引用。爲了解決這個問題,10g中使用了另外一種方法來解決-命名查詢塊。查詢優化器能夠給每一個查詢生成一個查詢塊名,並且還可使用提示qb_name手工爲每一個查詢塊命名。大多數提示均可以經過參數來指定在那個查詢塊中有效。
*在提示中經過@來引用一個查詢塊。
Oracle在11g的版本中提供了一個數據字典—V$SQL_HINT。經過這個數據字典能夠看到提示的出現版本、概要數據版本、SQL特性以及相反提示等。
這個hint相反操做的hint。
表明着這個hint正式公佈引入的版本。
當對優化器爲某個語句所制定的基本執行計劃不滿意時,最好的辦法就是經過提示來轉換優化器的模式,並觀察其轉換後的結果,看是否已經達到指望程度。若是隻經過轉換優化器的模式就能夠得到很是好的執行計劃,則就沒有必要額外使用更爲複雜的提示了。
這個提示的做用就是使咱們在某條語句中指定某個系統參數值。
爲實現查詢語句總體最優化而引導優化器制定最少成本的執行計劃。這個提示會使優化器選擇一條可最快檢索全部查詢行的路徑,而代價就是在檢索一行數據時,速度很慢。
爲得到最佳響應時間而引導優化器制定最少成本的執行計劃。這個提示會使優化器選擇可最快檢索出查詢的第一行(或指定行)數據的路徑,而代價就是檢索不少行時速度就會很慢。利用FIRST_ROWS來優化的行數,默認值爲1,這個值介於10到1000之間,這個使用FIRST_ROWS(n)的新方法是徹底基於代價的方法。它對n很敏感,若是n值很小,CBO就會生成包含嵌套循環以及索引查找的計劃;若是n很大,CBO會生成由哈希鏈接和全表掃描組成的計劃(相似ALL_ROWS)。
依據SQL中所使用到的表的統計信息存在與否,來決定使用RBO仍是CBO。在CHOOSE模式下,若是可以參考表的統計信息,則將按照ALL_ROWS方式執行。除非在查詢中的全部表都沒有通過分析,不然choose提示會對整個查詢使用基於代價的優化。若是在多表鏈接中有一個表通過分析過,那麼就會對整個查詢進行基於代價的優化。
使用基於規則的優化器來實現最優化執行,即引導優化器根據優先順序規則來決定查詢條件中所使用到的索引或運算符的執行順序來制定執行計劃。這個提示強制oracle優先使用預約義的一組規則,而不是對數據進行統計;同時該提示還會使這個語句避免使用其餘提示,除了DRIVING_SITE和ORDERED(無論是否進行基於規則的優化,這兩個提示均可使用)。
告訴優化器經過全表掃描方式訪問數據。這個提示只對所指定的表進行全表掃描,而不是查詢中的全部表。FULL提示能夠改善性能。這主要是由於它改變了查詢中的驅動表,而不是由於全表掃描。在使用其餘某些提示時,也必須使用FULL提示。只有訪問整個表時,纔可利用CACHE提示將表進行緩存。並行組中的某些提示也必須使用全表掃描。
引導優化器經過掃描聚簇索引來從索引表中讀取數據。
引導優化器按照哈希掃描的方式從表中讀取數據。
告訴優化器對指定表經過索引的方式訪問數據。當訪問數據會致使結果集不完整時,優化器將忽略這個Hint。
告訴優化器對指定表不容許使用索引。這個提示會禁止優化器使用指定索引。能夠在刪除沒必要要的索引以前在許多查詢中禁止索引。若是使用了NO_INDEX,可是沒有指定任何索引,則會執行全表掃描。若是對某個索引同時使用了NO_INDEX和會之產生衝突的提示(如INDEX),這時兩個提示都會被忽略掉。
利用索引從表中讀取數據時,引導優化器對提示中所指定索引的索引列值按照升序使用範圍掃描。
告訴優化器強制選擇位圖索引。這個提示會使優化器合併表上的多個位圖索引,而不是選擇其中最好的索引(這是INDEX提示的用途)。還可使用index_combine指定單個索引(對於指定位圖索引,該提示優先於INDEX提示)。對於B樹索引,可使用AND_EQUAL提示而不是這個提示。
索引關聯,當謂詞中引用的列上都有索引的時候,能夠經過索引關聯的方式來訪問數據。這個提示能夠將同一個表的各個不一樣索引進行合併,這樣就只須要訪問這些索引就能夠了,節省了回表查詢的時間。但只能在基於代價的優化器中使用該提示。這個提示不只容許只訪問表上的索引,這樣能夠掃描更少的代碼塊,而且它比使用索引並經過rowid掃描整個錶快5倍。
利用索引從表中讀取數據時,引導優化器對提示中所指定索引的索引列值按照降序使用範圍掃描。
告訴優化器以INDEX FFS(index fast full scan)的方式訪問數據。INDEX_FFS提示會執行一次索引的快速全局掃描。這個提示只訪問索引,而不是對應的表。只有查詢須要檢索的信息都在索引上時,才使用這個提示。特別在表有不少列時,使用該提示能夠極大地改善性能。
強制使用index skip scan的方式訪問索引。當在一個聯合索引中,某些謂詞條件並不在聯合索引的第一列時(或者謂詞並不在聯合索引的第一列時),能夠經過index skip scan來訪問索引得到數據。當聯合索引第一列的惟一值不多時,使用這種方式比全表掃描的方式效率要高。
將含有多個OR或者IN運算符所鏈接起來的查詢語句分解爲多個單一查詢語句,併爲每一個單一查詢語句選擇最優化查詢路徑,而後再將這些最優化查詢路徑結合在一塊兒,以實現總體查詢語句的最優化目的。只有在驅動查詢條件中包含OR的時候,纔可使用該提示。
引導優化器不要爲使用OR運算符號(或IN運算符)的條件制定相互結合的執行計劃。正好和USE_CONCAT相反。
當錶鏈接的對象是數據量比較大的表或者須要得到使用統計函數處理過的結果時,爲了提升執行速度可預先建立物化視圖。當用戶要求查詢某個查詢語句時,優化器會在從表中和從物化視圖中讀取數據的兩種方法中選擇一個更有效的方法來讀取數據。該執行方法稱之爲查詢重寫。使用REWRITE提示引導優化器按照該方式執行。
爲了能以最優方式從視圖或者嵌套視圖中讀取數據,經過變換查詢語句來直接讀取視圖使用的基表數據,該過程被稱之爲視圖合併。不一樣的狀況其具體使用類型也有所不一樣。該提示主要在視圖未發生合併時被使用。尤爲是對比較複雜的視圖或者嵌套視圖(好比使用了GROUP BY或DISTINC的視圖)使用該提示,有時會取得很是好的效果。
提示優化器將子查詢轉換爲鏈接的方式。也就是引導優化器合併子查詢和主查詢而且將其向鏈接類型轉換。
引導優化器讓子查詢可以獨立地執行完畢以後再跟外圍的查詢作FILTER。
使用該提示能夠將視圖或嵌套視圖之外的查詢條件推入到視圖以內。
使用該提示確保視圖或嵌套視圖之外的查詢條件不被推入到視圖內部。
使用該提示引導優化器爲不能合併的子查詢制定執行計劃。不能合併的子查詢被優先執行以後,該子查詢的執行結果將扮演縮減主查詢數據查詢範圍的提供者角色。一般在沒法執行子查詢合併的狀況下,子查詢扮演的都是檢驗者角色,因此子查詢通常被放在最後執行。在沒法被合併的子查詢擁有較少的結果行,或者該子查詢能夠縮減主查詢查詢範圍的狀況下,可使用該提示引導優化器最大程度地將該子查詢放在前面執行,以提升執行速度。但若是子查詢執行的是遠程表或者排序合併鏈接的一部分鏈接結果,則該提示將不起任何做用。
使用該提示將引導優化器將不能實現合併的子查詢放在最後執行。在子查詢沒法縮減主查詢的查詢範圍,或者執行子查詢開銷較大的狀況下,將這樣的子查詢放在最後執行能夠在某種程度上提升總體的執行效率。也就是說,儘量地使用其餘查詢條件最大程度地縮減查詢範圍以後,再執行子查詢。
這些提示能夠調整錶鏈接的順序。調整錶鏈接的順序並非只能使用這些提示,在嵌套循環鏈接方式中也可讓提示來引導優化器使用由驅動查詢條件所建立的索引。然而,該方法只有在使用的索引和錶鏈接順序同時被調整的狀況下才比較有效。通常而言,這些提示主要在執行多表鏈接和表之間的鏈接順序比較混亂的狀況下才使用,也在排序合併鏈接或哈希鏈接方式下,爲引導優化器優先執行數據量比較少得表時使用。
在一個多表關聯的查詢中,這個Hint指定由哪一個表做爲驅動表,即告訴優化器首先要訪問那個表上的數據。引導優化器使用LEADING指定的表做爲錶鏈接順序中的第一個表。該提示既與FROM中所描述的表的順序無關,也與做爲調整錶鏈接順序的ORDERED提示不一樣,而且在使用該提示時並不須要調整FROM中所描述的表的順序。當該提示與ORDERED提示同時使用時,該提示被忽略。
這個提示相似ORDERED提示,它容許指定驅動查詢的表,而後由優化器來判斷下一個要訪問的表。若是使用這個提示指定多張表,那麼就能夠忽略這個提示。
引導優化器按照FROM中所描述的表的順序執行鏈接。若是和LEADING提示被一塊兒使用,則LEADING提示將被忽略。因爲ORDERED只能調整錶鏈接的順序並不能改變錶鏈接的方式,因此爲了改變表的鏈接方式,常常將USE_NL、USE_MERGE提示與ORDERED提示放在一塊兒使用。
使用該提示引導優化器按照嵌套循環鏈接方式執行錶鏈接。它只是指出錶鏈接的方式,對於錶鏈接順序不會有任何影響。
引導優化器按照排序合併鏈接方式執行鏈接。在有必要的狀況下,推薦將該提示與ORDERED提示一塊兒使用。提示一般用於得到查詢的最佳吞吐量。假設將兩個錶鏈接在一塊兒,從每一個表返回的行集將被排序,而後再被合併(也就是合併排序),從而組成最終的結果集。因爲每一個行先被排序以後才進行合併,因此在給定查詢中檢索全部行時,速度將會最快。若是須要以最快速度返回第一行,就應該使用USE_NL提示。
該提示引導優化器按照哈希鏈接方式執行鏈接。在執行哈希鏈接時,若是因爲某一邊的表比較小,從而能夠在內存中實現哈希鏈接,那麼就可以得到很是好的執行速度。因爲在大部分狀況下優化器會經過對統計信息的分析來決定Build Input和Prove Input,因此建議不要使用ORDERED提示隨意改變表的鏈接順序。可是當優化器沒能作出正確判斷時,或者像從嵌套視圖中所得到的結果集合那樣不具有統計信息時,可使用該提示。
指定SQL執行的並行度,這個值將會覆蓋表自身設定的並行度。若是這個值爲default,CBO使用系統參數。從表中讀取大量數據和執行DML操做時使用該提示來指定SQL的並行操做。
通常狀況下須要在該提示中指定將要使用的並行線程個數。若是在該提示中沒有指定並行度的個數,則優化器將使用PARALLEL_THREADS_PER_CPU參數所指定的值進行自動計算。若是在定義表時指定了PARALLEL,那麼在可以使用並行操做的狀況下,即便沒有使用該提示,優化器也會按照指定的並行級別選擇並行操做。
可是若是想在DELETE、INSERT、UPDATE、MERGE等DML操做中使用並行操做,則必需要在會話中設置ALTER SESSION ENABLE PARALLEL DML。在某個會話中所設置的並行級別也能夠被引用在內部的GROUP BY或者排序操做中。在並行操做中若是出現了某個限制要素,則該提示將被忽略。
在SQL語句禁止使用並行。在有些版本中用NO_PARALLEL提示來代替NOPARALLEL提示。
爲了提升並行鏈接的執行速度,使用該提示來定義使用何種方法在主從進程之間(例如生產者進程和消費者進程)分配各鏈接表的數據行。
爲了按照並行操做的方式對分區索引進行索引範圍掃描而使用該提示,而且能夠指定進程的個數。
讓數據庫以直接加載的方式(direct load)將數據加載入庫。這個提示不會檢查當前是否有插入所須要的塊空間,相反它會直接將數據添加到新塊中。這樣會浪費空間,但能夠提升插入的性能。須要注意的是,數據將被存儲在HWM之上的位置。
在11.2中,Oracle新增了APPEND_VALUES提示,使得INSERT INTO VALUES語句也可使用直接路徑插入。
在全表掃描以後,數據塊將留在LRU列表的最活躍端。若是設置表的CACHE屬性,它的做用和HINT同樣。這個提示會將全表掃描所有緩存到內存中。若是表很大,會佔用大量內存。所以適用於用戶常常訪問的較小的表。
引導優化器將經過全表掃描方式獲取的數據塊緩存在LRU列表的最後位置,這樣可讓數據庫實例緩存中的這些數據塊被優先清除。這是優化器在Buffer Cache中管理數據塊的默認方法(僅針對全表掃描)。
使用該提示爲查詢語句塊命名,在其餘查詢語句塊能夠直接使用該查詢語句塊的名稱。
這個提示在分佈式數據庫操做中有用。指定表是處理鏈接所在的位置。能夠限制經過網絡處理的信息量。此外,還能夠創建遠程表的本地視圖來限制從遠程站點檢索的行。本地視圖應該有where子句,從而視圖能夠在將行發送回本地數據庫以前限制從遠程數據庫返回的行。
提示SQL執行時動態採樣的級別。這個級別爲0~10,它將覆蓋系統默認的動態採樣級別。等級越高,所得到統計信息的準確率越高。該提示的功能就是爲了確保將動態採樣原理應用在單個SQL中。
這個提示會使優化器合併表上的多個索引,而不是選擇其中最好的索引(這是INDEX提示的用途)。這個提示與前面的INDEX_JOIN提示有區別,以此指定的合併索引隨後需訪問表,而INDEX_JOIN提示則只需訪問索引。若是發現需常常用到這個提示,可能須要刪除這些單個索引而改用一個組合索引。須要查詢條件裏面包括全部索引列,而後取得每一個索引中獲得的rowid列表。而後對這些對象作merge join,過濾出相同的rowid後再去表中獲取數據或者直接從索引中得到數據。在10g中,and_equal已經廢棄了,只能經過hint才能生效。
向優化器提供對某個查詢語句的總體或部分的預測基數值,並經過參考該基數值來爲查詢語句制定執行計劃。若是在該提示中沒有指定表的名稱,則該基數值將被視爲從該查詢語句所得到的最終結果行數。
下面經過一個例子說明一下提示的使用及在什麼狀況下提示會被忽略。
*在某些狀況下,若是CBO認爲Hint會致使錯誤結果,那麼Hint則會忽略。該例子中由於ID字段可能爲空,而索引是保存空值的,所以count(*)使用索引將致使錯誤的結果,故而使用了全表掃描,忽略了Hint。
*ID字段不可爲空,所以COUNT可用索引掃描的方式處理,Hint生效了。
做者:韓鋒