sql性能調優(總結)

sql性能調整-總結

每種類型的語句都需要以下階段:
第一步,創建遊標
第二步,分析語句Parse the statement
第五步,綁定變量bind any variables
第七步,運行語句run the statement
第九步,關閉遊標close thecursor
如果使用了並行功能,還包含:
第六步,並行執行語句parallelize the statement
如果是查詢語句,還需要:
第三步,描述查詢的結果集describe results of a query
第四步,定義查詢的輸出數據define output of a query
第八步,取查詢出來的行fetch rows of a query

分析語句階段的操作:
翻譯sql語句,驗證合法性(書寫是否正確)
實現數據字典的查找,驗證是否符合表和列的定義
在所要求對象上獲取語法分析鎖,使語句在語法分析過程中不改變對象的定義
驗證爲存取所涉及的模式對象所需的權限是否滿足
決定語句的最佳執行計劃
將他裝入共享sql區
將分佈的語句全部或部分路由到包含所涉及數據的遠程節點


下面就是基於規則的優化器使用的執行路徑與各個路徑對應的等級:
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認爲越往下執行的代價越大,即等級越低
基於規則的索引按照上面的順序進行查找,有等級低的優先使用

 


重新分析表:
analyze table tablename compute statistics for table;
基於代價的優化器需要定期對錶進行重新分析,一週左右即可。

 


判斷當前數據庫使用何種優化器:
主要是由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新引入的。

==============================================
執行計劃

1.共享sql語句:
執行一條sql語句時,若內存中存在與之完全相同的語句及對應的執行計劃,則直接得到該語句的執行計劃。
這要求有大的共享池(shared_buffer_pool)並儘可能的使用綁定變量的方法執行sql語句。

2.recursive sql 爲了執行用戶發出的一個sql,oracle可能執行的一些額外操作

3.row source 行源
查詢中由上一個操作返回的符合條件的行的集合

4.predicate 謂詞
一個查詢中的where限制條件

5.driving table驅動表(outer table)
where後面的表或行源(row source 1)

6.probed table 被探查表(inner table)
在驅動表中得到具體一行的數據後,從該表中尋找符合連接條件的行。row source 2

7.組合索引 concatenated index
索引由多列組成

8.可選擇性selectivity
唯一鍵的數量/表中的行數 比值越接近1,該列的可選擇性越高,越適合建立索引。


執行計劃可以通過樹狀圖來表現,如果父步驟只需要單一的子步驟就可執行,可以在樹上串聯上去,使用first_rows作爲優化目標。
對每個由子步驟依次檢索出來的每一行,oracle就實現父步驟及所有串聯在一起的步驟一次。

有些父步驟在被實現之前需要子步驟的所有行,直到所有子步驟返回之前oracle不能實現該父步驟。包括排序、排序與合併的連接,組功能和總計,這些不能使用first_rows,可使用all_rows作爲優化目標

訪問路徑--access path
在物理層oracle讀取數據的最小單位是數據塊,一次讀取的最大值有操作系統一次I/O的最大值和multiblock參數共同決定

邏輯上訪問數據的方法:
(1)全表掃描Full Table Scans (FTS)
順序讀取分配給表的每個數據塊,直到最高水位線(HWM);多塊讀操作可以是一次I/O讀取多個數據塊。只有全表掃描可以使用多塊讀操作。
delete不會改變HWM,全表掃描時間不會縮短;truncate可以收縮HWM。10g以後可以人工收縮HWM。

全表掃描用於數據較少或數據量超過總量的5%-10%

(2)通過ROWID的表存取Table Access By ROWID
rowid指出了該行所在的數據文件、數據塊以及行在塊中的位置,rowid是獲取單行數據的最快方法
一次I/O只讀取一個數據塊。

(3)索引掃描(Index Scan)
通過index查找到數據所對應的rowid值,在根據rowid直接從表中得到具體的數據。
索引除了存儲每個索引的值外,還存儲其對應的rowid
索引掃描先掃描索引得到rowid,再根據rowid找到相對應的數據。由於索引經常使用,一般是在內存中的,這一步經常是邏輯I/O,而第二步如果表比較大,一般都是物理I/O,相對費時,因此若用索引讀取總數據的5%-10%以上的數據,索引效率下降很快。

 

根據索引的類型與where限制條件的不同,有4種類型的索引掃描:
索引唯一掃描(index unique scan)
索引範圍掃描(index range scan)
索引全掃描(index full scan)
索引快速掃描(index fast full scan)


(1)索引唯一掃描index unique scan
如果要對含有某個索引的行爲基礎創建聯合索引,索引的返回值通常是一行

(2)索引範圍掃描index range scan
分爲三種:
在唯一索引列上使用了range操作符<、>等
組合索引上只使用了部分列進行查詢,導致查詢出多行
對非唯一索引列上進行的任何查詢

(3)索引全掃描index full scan
只在CBO模式下有效。CBO通過數據統計得知進行全索引掃描比全表掃描更有效時才使用,且此時查詢出的數據必須都從索引中直接得到

(4)索引快速掃描index fast full scan
可以使用多塊讀功能,也可使用並行讀入,以獲取最大吞吐量和縮短執行時間。


表之間的連接
join是一種試圖將兩個表結合在一起的謂詞,一次只能連接兩個表(row source)。
row resource之間的連接順序對查詢效率有很大的影響,先存取特定表作爲驅動表,獲得較小的row source,可以提高效率。

根據連接條件可分爲等值連接、非等值連接、外連接
根據連接類型分爲:
排序--合併連接 sort merge join(SMJ)
嵌套循環nested loops(NL)
哈希連接hash join


排序 - - 合併連接(Sort Merge Join, SMJ)
內部連接過程:
1) 首先生成row source1需要的數據,然後對這些數據按照連接操作關聯列(如A.col3)進行排序。
2) 隨後生成row source2需要的數據,然後對這些數據按照與sort source1對應的連接操作關聯列(如B.col4)進行排序。
3) 最後兩邊已排序的行被放在一起執行合併操作,即將2個row source按照連接條件連接起來
排序費時、費資源,但如果2個row resource都已經排序了,SMJ連接方法效率還是很高的

嵌套循環NL
一般選擇能夠產生較少row resource的表作爲驅動表,進行2層的嵌套循環效率比較高。但有時不遵守此規律。
優點是:可以先返回已經連接的行,不必等待所有的連接操作處理完才返回數據。

哈希連接,理論上比SMJ、NL效率高,只用在CBO優化器中。使哈希連接生效,要設置HASH_JOIN_ENABLED=TRUE,還要注意hash_area_size參數。


應用範圍:
排序--合併連接(SMJ)
a)非等值連接
b)關聯列上都有索引,效果更好
c)將兩個較大的row source做連接,比NL效果好
d)如果sort merge返回的row source過大,會導致使用過多的rowid,性能下降

嵌套循環(NL)
a)在driving row source(外部表)比較小,在inner row source(內部表)上有唯一索引或高選擇性非唯一索引時,效率較高

哈希連接(HJ)
a)在2個較大的row source 之間連接時會取得相對較好的效率,一個row source較小時效率更好
b)只能用於等值連接中


笛卡爾積
一般是由於編碼時忘了寫關聯條件,執行計劃中帶有cartesian,得到的結果是幾個結果的乘積。

如何產生執行計劃:
1.
set autotrace on
sql語句
若不想看到執行結果,只看執行計劃,執行
set autotrace traceonly


如果執行該語句時遇到錯誤,解決方法爲:
(1)在要分析的用戶下:
Sqlplus > @ ?\rdbms\admin\utlxplan.sql
(2) 用sys用戶登陸 31
Sqlplus > @ ?\sqlplus\admin\plustrce.sql
Sqlplus > grant plustrace to user_name; - - user_name是上面所說的分析用戶

2.用explain plan命令
(1) sqlplus > @ ?\rdbms\admin\utlxplan.sql
(2) sqlplus > explain plan set statement_id =’???’ for select ………………
此方法並不執行sql語句,所以只會列出執行計劃,不會列出統計信息,並且執行計劃只存在plan_table中

找出耗資源的語句:
SELECT ADDRESS,
substr(SQL_TEXT,1,20) Text,
buffer_gets,
executions,
buffer_gets/executions AVG
FROM v$sqlarea
WHERE executions>0
AND buffer_gets > 100000
ORDER BY 5;


3.用dbms_system存儲過程生成執行計劃

Optimizer=CHOOSE 指明這個查詢的optimizer_mode,即optimizer_mode初始化參數指定的值,它並不是指語句執行時真的使用了該優化器。決定該語句使用何種優化器的唯一方法是看後面的cost部分。
如果cost有值,則是CBO模式;如果cost部分爲空或沒有cost,則使用的是RBO模式。
特別的,如果Optimizer=ALL_ROWS| FIRST_ROWS| FIRST_ROWS_n,則使用的是CBO優化器;如果Optimizer=RULE,則使用的是RBO優化器。

 

得到執行計劃中哪個表應該爲驅動表:
在執行計劃中,需要知道哪個操作是先執行的,哪個操作是後執行的,這對於判斷哪個表爲驅動表有用處。判斷之前,如果對錶的訪問是通過rowid,且該rowid的值是從索引掃描中得來得,則將該索引掃描先從執行計劃中暫時去掉。然後在執行計劃剩下的部分中,判斷執行順序的指導原則就是:最右、最上的操作先執行

 


CBO根據統計信息選擇驅動表,假如沒有統計信息,則在from 子句中從左到右的順序選擇驅動表

 


----------------------------------------
使用hint提示干預執行計劃

 

基於代價的優化器絕大多數時間可以提供正確的優化器,但有時不夠優化,需要人工干預。
用hint可實現的功能:
(1)使用優化器的類型
(2)基於代價的優化器的優化目標,是all_rows還是first_row
(3)表的訪問路徑,是全表掃描、索引掃描還是直接利用rowid
(4)表之間的連接類型
(5)表之間的連接順序
(6)語句的並行程度


使用CBO或HINTS提示,最好對錶和索引進行定期的分析

hints只應用在它們所在sql語句塊(statement block,由select update delete關鍵字標識)上,對其他語句或語句的其他部分沒有影響。
可以使用註釋comment來爲一個語句添加hints,一個語句只能有一個註釋,且只能在select 、update、delete關鍵字後面

語法:
delete|insert|select|update /*+hint [text][hint[text]]……*/
或者語句在一行的話,使用“--”作爲註釋符

注意:
+表示該註釋是一個hints,且“/*”與“+”間不能有空格
text是其他說明hint的註釋行文本
如果沒有正確指定hints,oracle忽略該hints,並不報錯


使用全套的hints
爲了確保優化器產生最優的執行計劃,可能不但指定要使用的索引,而且指定連接方式與連接順序等

指定優化器的方法與目標的hints
all_rows  基於代價的優化器,以吞吐量爲目標
first_rows(n) 基於代價的優化器,以響應時間爲目標
choose   根據是否有統計信息,選擇不同的優化器
rule    使用基於規則的優化器


(1)指定存儲路徑的hints:
/*+FULL(table)*/  指定該表使用全表掃描
/*+ROWID(table)*/ 指定該表使用rowid存取方法,用的較少
/*+INDEX(table[index])*/ 使用該表上指定的索引對錶進行索引掃描
/*+INDEX_FFS(table[index]))*/ 使用快速全表掃描
/*+NO_INDEX(table[index])*/   不適用該表上指定的索引進行存取,仍可使用其他的索引進行掃描

(2)指定連接順序的hints
/*+ordered*/ 按from子句中表的順序從左到右的連接
/*+star*/ 指示優化器使用星型查詢

(3)指定連接類型的hints:
/*+USE_NL(table[,table,……])*/  使用嵌套連接
/*+USE_MERGE(table[,table,……])*/ 使用排序-合併連接
/*+USE_HASH(table[,table,……])*/ 使用HASH連接


對於use_nl與use_hash,建議同ordered提示一起使用,否則不容易指定哪個表是驅動表

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

 

其他注意事項

不管optimizer_mode參數設爲什麼,只要滿足三個條件,就是用CBO
1)使用index only tables(IOTs),自動使用CBO
2)如果表上的paralle degree option設爲>1,自動使用CBO,不管是否用rule hints
3)除rule外的任何hints都將導致自動使用CBO執行語句


總結一下,一個語句在運行時到底使用何種優化器可以從下面的表格中識別出來,從上到下看你的語句到底是否滿足description列中描述的條件:
Description 對象是否被分析 優化器的類型
~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~
Non-RBO Object (Eg:IOT) n/a #1
Parallelism > 1 n/a #1
RULE hint n/a RULE
ALL_ROWS hint n/a ALL_ROWS
FIRST_ROWS hint n/a FIRST_ROWS
*Other Hint n/a #1
OPTIMIZER_GOAL=RULE n/a RULE
OPTIMIZER_GOAL=ALL_ROWS n/a ALL_ROWS
OPTIMIZER_GOAL=FIRST_ROWS n/a FIRST_ROWS
OPTIMIZER_GOAL=CHOOSE NO RULE
OPTIMIZER_GOAL=CHOOSE YES ALL_ROWS
#1 表示除非OPTIMIZER_GOAL 被設置爲FIRST_ROWS ,否則將使用ALL_ROWS。在PL/SQL中,則一直是使用ALL_ROWS
*Other Hint 表示是指除RULE、ALL_ROWS 和FIRST_ROWS以外的其它提示
2) 當CBO選擇了一個次優化的執行計劃時, 不要同CBO過意不去, 先採取如下措施:
a) 檢查是否在表與索引上又最新的統計數據
b) 對所有的數據進行分析,而不是隻分析一部分數據
c) 檢查是否引用的數據字典表,在oracle 10G之前,缺省情況下是不對數據字典表進行分析的。
d) 試試RBO優化器,看語句執行的效率如何,有時RBO能比CBO產生的更好的執行計劃
e) 如果還不行,跟蹤該語句的執行,生成trace信息,然後用tkprof格式化trace信息,這樣可以得到全面的供優化的信息。
3) 假如利用附錄的方法對另一個會話進行trace,則該會話應該爲專用連接
4) 不要認爲綁定變量(bind variables)的缺點只有書寫麻煩,而優點多多,實際上使用綁定
53
變量雖然避免了重複parse,但是它導致優化器不能使用數據庫中的列統計,從而選擇了較差的執行計劃。而使用硬編碼的SQL則可以使用列統計。當然隨着CBO功能的越來越強,這種情況會得到改善。目前就已經實現了在第一次運行綁定變量的sql語句時,考慮列統計。
5) 如果一個row source 超過10000行數據,則可以被認爲大row source
6) 有(+)的表不是driving table,注意:如果有外聯接,而且order hint指定的順序與外聯結決定的順序衝突,則忽略order hint
7) 影響CBO選擇execution plan的初始化參數:
這些參數會影響cost值
ALWAYS_ANTI_JOIN
B_TREE_BITMAP_PLANS
COMPLEX_VIEW_MERGING
DB_FILE_MULTIBLOCK_READ_COUNT
FAST_FULL_SCAN_ENABLED
HASH_AREA_SIZE
HASH_JOIN_ENABLED
HASH_MULTIBLOCK_IO_COUNT
OPTIMIZER_FEATURES_ENABLE
OPTIMIZER_INDEX_CACHING
OPTIMIZER_INDEX_COST_ADJ
OPTIMIZER_MODE> / GOAL
OPTIMIZER_PERCENT_PARALLEL
OPTIMIZER_SEARCH_LIMIT
PARTITION_VIEW_ENABLED
PUSH_JOIN_PREDICATE
SORT_AREA_SIZE
SORT_DIRECT_WRITES
SORT_WRITE_BUFFER_SIZE
STAR_TRANSFORMATION_ENABLED
V733_PLANS_ENABLED
CURSOR_SHARING


===============================
附錄:

如何通過跟蹤一個客戶端程序發出的sql的方法來優化SQL


簡要說來,跟蹤一個客戶程序發出的SQL主要分成下面幾步:
1) 識別要跟蹤的客戶端程序到數據庫的連接(後面都用session代替),主要找出能唯一識別一個session的sid與serial#.
2) 設定相應的參數,如打開時間開關(可以知道一個sql執行了多長時間),存放跟蹤數據的文件的位置、最大值。
3) 啓動跟蹤功能
4) 讓系統運行一段時間,以便可以收集到跟蹤數據
5) 關閉跟蹤功能
6) 格式化跟蹤數據,得到我們易於理解的跟蹤結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章