分析執行計劃最佳化SQLORACLE的最佳化器(轉)

jss001發表於2009-03-04
最佳化器有時也被稱為查詢最佳化器,這是因為查詢是影響資料庫效能最主要的部分,不要以為只有SELECT語句是查詢。實際上,帶有任何WHERE條件的DML(INSERT、UPDATE、DELETE)語句中都包含查詢要求,在後面的文章中,當說到查詢時,不一定只是指SELECT語句,也有可能指DML語句中的查詢部分。最佳化器是所有關聯式資料庫引擎中的最神秘、最富挑戰性的部件之一,從效能的角度看也是最重要的部分,它效能的高低直接關係到資料庫效能的好壞。

我們知道,SQL語句同其它語言(如C語言)的語句不一樣,它是非過程化(non-procedural)的語句,即當你要取資料時,不需要告訴資料庫透過何種途徑去取資料,如到底是透過索引取資料,還是應該將表中的每行資料都取出來,然後再透過一一比較的方式取資料(即全表掃描),這是由資料庫的最佳化器決定的,這就是非過程化的含義,也就是說,如何取資料是由最佳化器決定,而不是應用開發者透過程式設計決定。在處理SQL的SELECT、UPDATE、INSERT或DELETE語句時,Oracle 必須訪問語句所涉及的資料,Oracle的最佳化器部分用來決定訪問資料的有效路徑,使得語句執行所需的I/O和處理時間最小。

為了實現一個查詢,核心必須為每個查詢定製一個查詢策略,或為取出符合條件的資料生成一個執行計劃(execution plan)。典型的,對於同一個查詢,可能有幾個執行計劃都符合要求,都能得到符合條件的資料。例如,參與連線的表可以有多種不同的連線方法,這取決於連線條件和最佳化器採用的連線方法。為了在多個執行計劃中選擇最優的執行計劃,最佳化器必須使用一些實際的指標來衡量每個執行計劃使用的資源(I/0次數、CPU等),這些資源也就是我們所說的代價(cost)。如果一個執行計劃使用的資源多,我們就說使用執行計劃的代價大。以執行計劃的代價大小作為衡量標準,最佳化器選擇代價最小的執行計劃作為真正執行該查詢的執行計劃,並拋棄其它的執行計劃。

在ORACLE的發展過程中,一共開發過2種型別的最佳化器:基於規則的最佳化器和基於代價的最佳化器。這2種最佳化器的不同之處關鍵在於:取得代價的方法與衡量代價的大小不同。現對每種最佳化器做一下簡單的介紹:

  基於規則的最佳化器 -- Rule Based (Heuristic) Optimization(簡稱RBO):

  在ORACLE7之前,主要是使用基於規則的最佳化器。ORACLE在基於規則的最佳化器中採用啟發式的方法(Heuristic Approach)或規則(Rules)來生成執行計劃。例如,如果一個查詢的where條件(where clause)包含一個謂詞(predicate,其實就是一個判斷條件,如”=”, “>”, ”
  如,對於select * from emp where deptno = 10這個查詢來說,如果是使用基於規則的最佳化器,而且deptno列上有有效的索引,則會透過deptno列上的索引來訪問emp表。在絕大多數情況下,這是比較高效的,但是在一些特殊情況下,使用索引訪問也有比較低效的時候,現舉例說明:
1) emp表比較小,該表的資料只存放在幾個資料塊中。此時使用全表掃描比使用索引訪問emp表反而要好。因為表比較小,極有可能資料全在記憶體中,所以此時做全表掃描是最快的。而如果使用索引掃描,需要先從索引中找到符合條件記錄的rowid,然後再一一根據這些rowid從emp中將資料取出來,在這種條件下,效率就會比全表掃描的效率要差一些。

2) emp表比較大時,而且deptno = 10條件能查詢出表中大部分的資料如(50%)。如該表共有4000萬行資料,共放在有500000個資料塊中,每個資料塊為8k,則該表共有約4G,則這麼多的資料不可能全放在記憶體中,絕大多數需要放在硬碟上。此時如果該查詢透過索引查詢,則是你夢魘的開始。db_file_multiblock_read_count引數的值200。如果採用全表掃描,則需要500000/db_file_multiblock_read_count=500000/200=2500次I/O。但是如果採用索引掃描,假設deptno列上的索引都已經cache到記憶體中,所以可以將訪問索引的開銷忽略不計。因為要讀出4000萬x 50% = 2000萬資料,假設在讀這2000萬資料時,有99.9%的命中率,則還是需要20000次I/O,比上面的全表掃描需要的2500次多多了,所以在這種情況下,用索引掃描反而效能會差很多。在這樣的情況下,用全表掃描的時間是固定的,但是用索引掃描的時間會隨著選出資料的增多使查詢時間相應的延長。

上面是枯燥的假設資料,現在以具體的例項給予驗證:
環境: oracle 817 + linux + 陣列櫃,表SWD_BILLDETAIL有3200多萬資料;
表的id列、cn列上都有索引
經檢視執行計劃,發現執行select count(id) from SWD_BILLDETAIL;使用全表掃描,執行完用了大約1.50分鐘(4次執行取平均,每次分別為1.45 1.51 2.00 1.46)。而執行select count(id) from SWD_BILLDETAIL where cn
下面就是基於規則的最佳化器使用的執行路徑與各個路徑對應的等級:
RBO Path 1: Single Row by Rowid(等級最高)
RBO Path 2: Single Row by Cluster Join
RBO Path 3: Single Row by Hash Cluster Key with Unique or Primary Key
RBO Path 4: Single Row by Unique or Primary Key
RBO Path 5: Clustered Join
RBO Path 6: Hash Cluster Key
RBO Path 7: Indexed Cluster Key
RBO Path 8: Composite Index
RBO Path 9: Single-Column Indexes
RBO Path 10: Bounded Range Search on Indexed Columns
RBO Path 11: Unbounded Range Search on Indexed Columns
RBO Path 12: Sort Merge Join
RBO Path 13: MAX or MIN of Indexed Column
RBO Path 14: ORDER BY on Indexed Column
RBO Path 15: Full Table Scan(等級最低)

上面的執行路徑中,RBO認為越往下執行的代價越大,即等級越低。在RBO生成執行計劃時,如果它發現有等級高的執行路徑可用,則肯定會使用等級高的路徑,而不管任何其它影響效能的元素,即RBO透過上面的路徑的等級決定執行路徑的代價,執行路徑的等級越高,則使用該執行路徑的代價越小。如上面2個例子所述,如果使用RBO,則肯定使用索引訪問表,也就是選擇了比較差的執行計劃,這樣會給資料庫效能帶來很大的負面影響。為了解決這個問題,從ORACLE 7開始oracle引入了基於代價的最佳化器,下面給出了介紹。

  基於代價的最佳化器 -- Cost Based Optimization(簡稱CBO)

Oracle把一個代價引擎(Cost Engine)整合到資料庫核心中,用來估計每個執行計劃需要的代價,該代價將每個執行計劃所耗費的資源進行量化,從而CBO可以根據這個代價選擇出最優的執行計劃。一個查詢耗費的資源可以被分成3個基本組成部分:I/O代價、CPU代價、network代價。I/O代價是將資料從磁碟讀入記憶體所需的代價。訪問資料包括將資料檔案中資料塊的內容讀入到SGA的資料快取記憶體中,在一般情況下,該代價是處理一個查詢所需要的最主要代價,所以我們在最佳化時,一個基本原則就是降低查詢所產生的I/O總次數。CPU代價是處理在記憶體中資料所需要的代價,如一旦資料被讀入記憶體,則我們在識別出我們需要的資料後,在這些資料上執行排序(sort)或連線(join)操作,這需要耗費CPU資源。

對於需要訪問跨節點(即通常說的伺服器)資料庫上資料的查詢來說,存在network代價,用來量化傳輸操作耗費的資源。查詢遠端表的查詢或執行分散式連線的查詢會在network代價方面花費比較大。

在使用CBO時,需要有表和索引的統計資料(分析資料)作為基礎資料,有了這些資料,CBO才能為各個執行計劃計算出相對準確的代價,從而使CBO選擇最佳的執行計劃。所以定期的對錶、索引進行分析是絕對必要的,這樣才能使統計資料反映資料庫中的真實情況。否則就會使CBO選擇較差的執行計劃,影響資料庫的效能。分析操作不必做的太頻繁,一般來說,每星期一次就足夠了。切記如果想使用CBO,則必須定期對錶和索引進行分析。

對於分析用的命令,隨著資料庫版本的升級,用的命令也發生了變換,在oracle 8i以前,主要是用ANALYZE命令。在ORACLE 8I以後,又引入了DBMS_STATS儲存包來進行分析。幸運的是從ORACLE 10G以後,分析工作變成自動的了,這減輕的DBA的負擔,不過在一些特殊情況下,還需要一些手工分析。

如果採用了CBO最佳化器,而沒有對錶和索引進行分析,沒有統計資料,則ORACLE使用預設的統計資料(至少在ORACLE 9I中是這樣),這可以從oracle的文件上找到。使用的預設值肯定與系統的實際統計值不一致,這可能會導致最佳化器選擇錯誤的執行計劃,影響資料庫的效能。

要注意的是:雖然CBO的功能隨著ORACLE新版本的推出,功能越來越強,但它不是能包治百病的神藥,否則就不再需要DBA了,那我就慘了!!!實際上任何一個語句,隨著硬體環境與應用資料的不同,該語句的執行計劃可能需要隨之發生變化,這樣才能取得最好的效能。所以有時候不在具體的環境下而進行SQL效能調整是徒勞的。

在ORACLE8I推出的時候,ORACLE極力建議大家使用CBO,說CBO有種種好處,但是在那是ORACLE開發的應用系統還是使用基於規則的最佳化器,從這件事上我們可以得出這樣的結論:1) 如果團隊的資料庫水平很高而且都熟悉應用資料的特點,RBO也可以取得很好的效能。2)CBO不是很穩定,但是一個比較有前途的最佳化器,Oracle極力建議大家用是為了讓大家儘快發現它的BUG,以便進一步改善,但是ORACLE為了對自己開發的應用系統負責,他們還是使用了比較熟悉而且成熟的RBO。從這個事情上給我們的啟發就是:我們在以後的開發中,應該儘量採用我們熟悉並且成熟的技術,而不要一味的採用新技術,一味採用新技術並不一定能開發出好的產品。幸運的是從ORACLE 10G後,CBO已經足夠的強大與智慧,大家可以放心的使用該技術,因為ORACLE 10G後,Oracle自己開發的應用系統也使用CBO最佳化器了。而且ORACLE規定,從ORACLE 10G開始,開始廢棄RBO最佳化器。這句話並不是指在ORACLE 10G中不能使用RBO,而是從ORACLE 10G開始開始,不再為RBO的BUG提供修補服務。

在上面的第2個例子中,如果採用CBO最佳化器,它就會考慮emp表的行數,deptno列的統計資料,發現對該列做查詢會查詢出過多的資料,並且考慮db_file_multiblock_read_count引數的設定,發現用全表掃描的代價比用索引掃描的代價要小,從而使用全表掃描從而取得良好的執行效能。

  判斷當前資料庫使用何種最佳化器:

主要是由optimizer_mode初始化引數決定的。該引數可能的取值為:first_rows_[1 | 10 | 100 | 1000] | first_rows | all_rows | choose | rule。具體解釋如下:
RULE為使用RBO最佳化器。
CHOOSE則是根據實際情況,如果資料字典中包含被引用的表的統計資料,即引用的物件已經被分析,則就使用CBO最佳化器,否則為RBO最佳化器。

ALL_ROWS為CBO最佳化器使用的第一種具體的最佳化方法,是以資料的吞吐量為主要目標,以便可以使用最少的資源完成語句。

FIRST_ROWS為最佳化器使用的第二種具體的最佳化方法,是以資料的響應時間為主要目標,以便快速查詢出開始的幾行資料。

FIRST_ROWS_[1 | 10 | 100 | 1000] 為最佳化器使用的第三種具體的最佳化方法,讓最佳化器選擇一個能夠把響應時間減到最小的查詢執行計劃,以迅速產生查詢結果的前 n 行。該引數為ORACLE 9I新引入的。

從ORACLE V7以來,optimizer_mode引數的預設設定應是"choose",即如果對已分析的表查詢的話選擇CBO,否則選擇RBO。在此種設定中,如果採用了CBO,則預設為CBO中的all_rows模式。

注意:即使指定資料庫使用RBO最佳化器,但有時ORACLE資料庫還是會採用CBO最佳化器,這並不是ORACLE的BUG,主要是由於從ORACLE 8I後引入的許多新特性都必須在CBO下才能使用,而你的SQL語句可能正好使用了這些新特性,此時資料庫會自動轉為使用CBO最佳化器執行這些語句。


  什麼是最佳化

最佳化是選擇最有效的執行計劃來執行SQL語句的過程,這是在處理任何資料的語句(SELECT,INSERT,UPDATE或DELETE)中的一個重要步驟。對Oracle來說,執行這樣的語句有許多不同的方法,譬如說,將隨著以什麼順序訪問哪些表或索引的不同而不同。所使用的執行計劃可以決定語句能執行得有多快。Oracle中稱之為最佳化器(Optimizer)的元件用來選擇這種它認為最有效的執行計劃。

由於一系列因素都會會影響語句的執行,最佳化器綜合權衡各個因素,在眾多的執行計劃中選擇認為是最佳的執行計劃。然而,應用設計人員通常比最佳化器更知道關於特定應用的資料特點。無論最佳化器多麼智慧,在某些情況下開發人員能選擇出比最佳化器選擇的最優執行計劃還要好的執行計劃。這是需要人工干預資料庫最佳化的主要原因。事實表明,在某些情況下,確實需要DBA對某些語句進行手工最佳化。

  注:從Oracle的一個版本到另一個版本,最佳化器可能對同一語句生成不同的執行計劃。在將來的Oracle 版本中,最佳化器可能會基於它可以用的更好、更理想的資訊,作出更優的決策,從而導致為語句產生更優的執行計劃。
[@more@]

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

相關文章