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

優化器有時也被稱爲查詢優化器,這是因爲查詢是影響數據庫性能最主要的部分,不要以爲只有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,其實就是一個判斷條件,如”=”, “>”, ”<”等),而且該謂詞上引用的列上有有效索引,那麼優化器將使用索引訪問這個表,而不考慮其它因素,如表中數據的多少、表中數據的易變性、索引的可選擇性等。此時數據庫中沒有關於表與索引數據的統計性描述,如表中有多上行,每行的可選擇性等。優化器也不考慮實例參數,如multi block i/o、可用排序內存的大小等,所以優化器有時就選擇了次優化的計劃作爲真正的執行計劃,導致系統性能不高。

  如,對於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 <'6';卻用了2個小時還沒有執行完,經分析該語句使用了cn列上的索引,然後利用查詢出的rowid再從表中查詢數據。我爲什麼不使用select count(cn) from SWD_BILLDETAIL where cn <'6';呢?後面在分析執行路徑的索引掃描時時會給出說明。

下面就是基於規則的優化器使用的執行路徑與各個路徑對應的等級:
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 版本中,優化器可能會基於它可以用的更好、更理想的信息,作出更優的決策,從而導致爲語句產生更優的執行計劃。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章