国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > Oracle > 正文

Oracle Tuning的一些總結

2024-08-29 13:31:35
字體:
來源:轉載
供稿:網友

    關于oracle的性能調整,一般包括兩個方面,一是指oracle數據庫本身的調整,比如sga、pga的優化設置,二是連接oracle的應用程序以及sql語句的優化。做好這兩個方面的優化,就可以使一套完整的oracle應用系統處于良好的運行狀態。
        本文主要是把一些oracle tuning的文章作了一個簡單的總結,力求以實際可操作為目的,配合講解部分理論知識,使大部分具有一般oracle知識的使用者能夠對oracle tuning有所了解,并且能夠根據實際情況對某些參數進行調整。關于更加詳細的知識,請參見本文結束部分所提及的推薦書籍,同時由于該話題內容太多且復雜,本文必定有失之偏頗甚至錯誤的地方,請不吝賜教,并共同進步。

1.  sga的設置
        在oracle tuning中,對sga的設置是關鍵。sga,是指shared global area , 或者是 system global area , 稱為共享全局區或者系統全局區,結構如下圖所示。


 
        對于sga區域內的內存來說,是共享的、全局的,在unix 上,必須為oracle 設置共享內存段(可以是一個或者多個),因為oracle 在unix上是多進程;而在windows上oracle是單進程(多個線程),所以不用設置共享內存段。

1.1  sga的各個組成部分
下面用 sqlplus 查詢舉例看一下 sga 各個組成部分的情況:
sql> select * from v$sga;
name                      value
--------------------              ----------
fixed size                   104936
variable size              823164928
database buffers          1073741824
redo buffers                 172032

或者
sql> show sga
total system global area   1897183720 bytes
fixed size                   104936 bytes
variable size              823164928 bytes
database buffers          1073741824 bytes
redo buffers                 172032 bytes

fixed size
        oracle 的不同平臺和不同版本下可能不一樣,但對于確定環境是一個固定的值,里面存儲了sga 各部分組件的信息,可以看作引導建立sga的區域。

variable size
        包含了shared_pool_size、java_pool_size、large_pool_size 等內存設置

database buffers
        指數據緩沖區,在8i 中包含db_block_buffer*db_block_size、buffer_pool_keep、buffer_pool_recycle 三部分內存。在9i 中包含db_cache_size、db_keep_cache_size、db_recycle_cache_size、db_nk_cache_size。

redo buffers
       指日志緩沖區,log_buffer。在這里要額外說明一點的是,對于v$parameter、v$sgastat、v$sga查詢值可能不一樣。v$parameter 里面的值,是指用戶在初始化參數文件里面設置的值,v$sgastat是oracle 實際分配的日志緩沖區大小(因為緩沖區的分配值實際上是離散的,也不是以block 為最小單位進行分配的),v$sga 里面查詢的值,是在oracle 分配了日志緩沖區后,為了保護日志緩沖區,設置了一些保護頁,通常我們會發現保護頁大小是8k(不同環境可能不一樣)。參考如下內容
sql> select substr(name,1,10) name,substr(value,1,10) value
       2 from v$parameter where name = 'log_buffer';
name                 value
--------------------  --------------------
log_buffer              163840

sql> select * from v$sgastat where pool is null;

pool        name                       bytes
----------- --------------------------                ----------
            fixed_sga                      104936
            db_block_buffers            1073741824
            log_buffer                     163840

sql> select * from v$sga;

name                      value
--------------------              ----------
fixed size                   104936
variable size               823164928
database buffers           1073741824
redo buffers                 172032

172032 – 163840 = 8192

(以上試驗數據是在 hp b.11.11 + oracle 8.1.7.4 環境下得到的)


1.2  sga的大小設置
       在對sga的結構進行簡單分析以后,下面是關于如何根據系統的情況正確設置sga大小的問題。
sga是一塊內存區域,占用的是系統物理內存,因此對于一個oracle應用系統來說,sga決不是越大越好,這就需要尋找一個系統優化的平衡點。


1.2.1  設置參數前的準備
在設置sga的內存參數之前,我們首先要問自己幾個問題
一:物理內存多大
二:操作系統估計需要使用多少內存
三:數據庫是使用文件系統還是裸設備
四:有多少并發連接
五:應用是oltp 類型還是olap 類型


根據這幾個問題的答案,我們可以粗略地為系統估計一下內存設置。那我們現在來逐個問題地討論,首先物理內存多大是最容易回答的一個問題,然后操作系統估計使用多少內存呢?從經驗上看,不會太多,通常應該在200m 以內(不包含大量進程pcb)。
接下來我們要探討一個重要的問題,那就是關于文件系統和裸設備的問題,這往往容易被我們所忽略。操作系統對于文件系統,使用了大量的buffer 來緩存操作系統塊。這樣當數據庫獲取數據塊的時候,雖然sga 中沒有命中,但卻實際上可能是從操作系統的文件緩存中獲取的。而假如數據庫和操作系統支持異步io,則實際上當數據庫寫進程dbwr寫磁盤時,操作系統在文件緩存中標記該塊為延遲寫,等到真正地寫入磁盤之后,操作系統才通知dbwr寫磁盤完成。對于這部分文件緩存,所需要的內存可能比較大,作為保守的估計,我們應該考慮在 0.2——0.3 倍內存大小。但是如果我們使用的是裸設備,則不考慮這部分緩存的問題。這樣的情況下sga就有調大的機會。
關于數據庫有多少并發連接,這實際上關系到pga 的大小(mts 下還有large_pool_size)。事實上這個問題應該說還跟oltp 類型或者olap 類型相關。對于oltp類型oracle 傾向于可使用mts,對于olap 類型使用獨立模式,同時olap 還可能涉及到大量的排序操作的查詢,這些都影響到我們內存的使用。那么所有的問題綜合起來,實際上主要反映在uga的大小上。uga主要包含以下部分內存設置
sql> show parameters area_size

name                                 type    value
------------------------------------               -------     --------
bitmap_merge_area_size                   integer    1048576
create_bitmap_area_size                   integer    8388608
hash_area_size                           integer     131072
sort_area_size                            integer     65536
sql>


在這部分內存中我們最關注的通常是sort_area_size,這是當查詢需要排序的時候,數據庫會話將使用這部分內存進行排序,當內存大小不足的時候,使用臨時表空間進行磁盤排序。由于磁盤排序效率和內存排序效率相差好幾個數量級,所以這個參數的設置很重要。
當出現大量排序時的磁盤i/o操作時,可以考慮增加sort_area_size的值。sort_area_size是oracle用于一次排序所需的最大內存數,在排序結束但是結果列返回之前,oracle會釋放sort_area_size大小的內存,但是會保留sort_area_retained_size大小的內存,知道最后一行結果列返回以后,才釋放所有的內存。
會導致排序的語句有 select distinct , minus , intersect , union 和 min()、max()、count() 操作;而不會導致排序的語句有 update , 帶between子句的select 等等。
這四個參數都是針對會話進行設置的,是單個會話使用的內存的大小,而不是整個數據庫使用的。偶爾會看見有人誤解了這個參數以為是整個數據庫使用的大小,這是極其嚴重的錯誤。假如設置了mts,則uga被分配在large_pool_size,也就是說放在了共享內存里面,不同進程(線程)之間可以共享這部分內存。在這個基礎上,我們假設數據庫存在并發執行server process 為100 個,根據上面我們4 個參數在oracle8.1.7 下的默認值,我們來計算獨立模式下pga 的大致大小。由于會話并不會經常使用create_bitmap_area_size 、bitmap_merge_area_size,所以我們通常不對四個參數求和。在考慮到除這四個參數外會話所保存的變量、堆棧等信息,我們估計為2m,則200 個進程最大可能使用200m 的pga。

1.2.2  一個經驗公式
       現在,根據上面這些假定,我們來看sga 實際能達到多少內存。在1g 的內存的服務器上,我們能分配給sga 的內存大約為400—500m。若是2g 的內存,大約可以分到1g的內存給sga,8g 的內存可以分到5g的內存給sga。當然我們這里是以默認的排序部分內存sort_area_size=64k進行衡量的,假如我們需要調大該參數和hash_area_size等參數,然后我們應該根據并發的進程的數量,來衡量考慮這個問題。

事實上,通常我們更習慣通過直觀的公式化來表達這樣的問題:
os 使用內存+sga+并發執行進程數*(sort_area_size+hash_ara_size+2m) < 0.7*總內存

(公式是死的,系統是活的,實際應用的調整不必框公式,這不過是一個參考建議)

在我們的實際應用中,假如采用的是裸設備,我們可適當的增大sga(如果需要的話)。由于目前幾乎所有的操作系統都使用虛擬緩存,所以實際上如果就算sga 設置的比較大也不會導致錯誤,而是可能出現頻繁的內存頁的換入與換出(page in/out)。在操作系統一級如果觀察到這個現象,那么我們就需要調整內存的設置。


1.2.3  各個參數的設置
那么sga中的各個參數具體應該按照什么樣的原則來設置呢,下面進行討論:
log_buffer
對于日志緩沖區的大小設置,通常我覺得沒有過多的建議,因為參考lgwr寫的觸發條件之后,我們會發現通常超過3m意義不是很大。作為一個正式系統,可能考慮先設置這部分為log_buffer=1—3m 大小,然后針對具體情況再調整。
large_pool_size
對于大緩沖池的設置,假如不使用mts,建議在20—30m 足夠了。這部分主要用來保存并行查詢時候的一些信息,還有就是rman 在備份的時候可能會使用到。如果設置了mts,則由于uga部分要移入這里,則需要具體根據session最大數量和 sort_ares_size 等相關會話內存參數的設置來綜合考慮這部分大小的設置,一般可以考慮為 session * (sort_area_size + 2m)。這里要提醒一點,不是必須使用mts,我們都不主張使用mts,尤其同時在線用戶數小于500的情況下。。
java_pool_size
假如數據庫沒有使用java,我們通常認為保留10—20m大小足夠了。事實上可以更少,甚至最少只需要32k,但具體跟安裝數據庫的時候的組件相關(比如http server)。
shared_pool_size
這是迄今為止最具有爭議的一部分內存設置。按照很多文檔的描述,這部分內容應該幾乎和數據緩沖區差不多大小。但實際上情況卻不是這樣的。首先我們要考究一個問題,那就是這部分內存的作用,它是為了緩存已經被解析過的sql,而使其能被重用,不再解析。這樣做的原因是因為,對于一個新的sql(shared_pool 里面不存在已經解析的可用的相同的sql),數據庫將執行硬解析,這是一個很消耗資源的過程。而若已經存在,則進行的僅僅是軟分析(在共享池中尋找相同sql),這樣消耗的資源大大減少。所以我們期望能多共享一些sql,并且如果該參數設置不夠大,經常會出現ora-04031錯誤,表示為了解析新的sql,沒有可用的足夠大的連續空閑空間,這樣自然我們期望該參數能大一些。但是該參數的增大,卻也有負面的影響,因為需要維護共享的結構,內存的增大也會使得sql 的老化的代價更高,帶來大量的管理的開銷,所有這些可能會導致cpu 的嚴重問題。

在一個充分使用綁定變量的比較大的系統中,shared_pool_size 的開銷通常應該維持在300m 以內。除非系統使用了大量的存儲過程、函數、包,比如oracle erp 這樣的應用,可能會達到500m甚至更高。于是我們假定一個1g內存的系統,可能考慮設置該參數為100m,2g 的系統考慮設置為150m,8g 的系統可以考慮設置為200—300m。
對于一個沒有充分使用或者沒有使用綁定變量系統,這可能給我們帶來一個嚴重的問題。所謂沒有使用bind var 的sql,我們稱為literal sql。也就是比如這樣的兩句sql我們認為是不同的sql,需要進行2 次硬解析:
select * from emp where name = ‘tom’;
select * from emp where name = ‘jerry’;
假如把 ’tom’ 和 ’jerry’ 換做變量v,那就是使用了bind var,我們可以認為是同樣的sql 從而能很好地共享。共享sql 本來就是shared_pool_size 這部分內存存在的本意,oracle的目的也在于此,而我們不使用bind var 就是違背了oracle 的初衷,這樣將給我們的系統帶來嚴重的問題。當然,如果通過在操作系統監控,沒有發現嚴重的cpu問題,我們如果發現該共享池命中率不高可以適當的增加shred_pool_size。但是通常我們不主張這部分內存超過800m(特殊情況下可以更大)。
事實上,可能的話我們甚至要想辦法避免軟分析,這在不同的程序語言中實現方式有差異。我們也可能通過設置session_cached_cursors 參數來獲得幫助(這將增大pga)
關于使用綁定變量的話題,在下面的應用優化中繼續討論。

data buffer
現在我們來談數據緩沖區,在確定了sga 的大小并分配完了前面部分的內存后,其余的,都分配給這部分內存。通常,在允許的情況下,我們都嘗試使得這部分內存更大。這部分內存的作用主要是緩存 db block,減少甚至避免從磁盤上獲取數據,在8i中通常是由db_block_buffers*db_block_size 來決定大小的。如果我們設置了buffer_pool_keep 和buffer_pool_recycle,則應該加上后面這兩部分內存的大小。

可以看出,設置sga時基本上應該掌握的原則是:
  data buffer 一般可以盡可能的大
  shared_pool_size 應該適度
  log buffer 在 1mb 以內就可以了

假定oracle是 32 bit ,服務器ram大于2g ,注意你的pga的情況,,則建議
shared_pool_size + data buffer +large_pool_size + java_pool_size < 1.6g

再具體化,如果512m ram
建議 shared_pool_size = 50m, data buffer = 200m

如果1g ram
shared_pool_size = 100m , data buffer = 500m

如果2g ram
shared_pool_size = 150m ,data buffer = 1.2g

物理內存再大已經跟參數沒有關系了

假定64 bit oracle
內存4g
shared_pool_size = 200m , data buffer = 2.5g

內存8g
shared_pool_size = 300m , data buffer = 5g

內存 12g
shared_pool_size = 300m-----800m , data buffer = 8g

1.3  32bit 與 64bit 對sga的影響
為什么在上面sga大小設置的經驗規則中要分 32bit oracle 和 64bit oracle 呢,是因為這關系到sga大小的上限問題。在32bit的數據庫下,通常oracle只能使用不超過1.7g的內存,即使我們擁有12g的內存,但是我們卻只能使用1.7g,這是一個莫大的遺憾。假如我們安裝64bit的數據庫,我們就可以使用很大的內存,幾乎不可能達到上限。但是64bit 的數據庫必須安裝在64bit 的操作系統上,可惜目前windows上只能安裝32bit的數據庫,我們通過下面的方式可以查看數據庫是 32bit 還是 64bit :
sql> select * from v$version;
banner
----------------------------------------------------------------
oracle8i enterprise edition release 8.1.7.0.0 - production
pl/sql release 8.1.7.0.0 - production
core 8.1.7.0.0 production
tns for 32-bit windows: version 8.1.7.0.0 - production
nlsrtl version 3.4.1.0.0 – production

在unix平臺下的顯示有所不同,明顯可以看出是 64bit oracle ,比如在hp-ux平臺上:
sql> select * from v$version;

banner
----------------------------------------------------------------
oracle8i enterprise edition release 8.1.7.4.0 - 64bit production
pl/sql release 8.1.7.4.0 - production
core    8.1.7.0.0       production
tns for hpux: version 8.1.7.4.0 - production
nlsrtl version 3.4.1.0.0 – production

32bit的oracle無論跑在32bit或者64bit的平臺都有sga的限制的,而對于32bit的平臺只能跑32bit的oracle,但是在特定的操作系統下,可能提供了一定的手段,使得我們可以使用超過1.7g 的內存,達到2g 以上甚至更多。由于我們現在一般都使用64bit oracle,因此關于如何在32bit平臺上擴展sga大小的問題不再贅述。


1.4  9i中相關參數的變化
oracle的版本的更新,總是伴隨著參數的變化,并且越來越趨向于使得參數的設置更簡單,因為復雜的參數設置使得dba們經常焦頭爛額。關于內存這部分的變化,我們可以考察下面的參數。事實上在9i中數據庫本身可以給出一組適合當前運行系統的sga相關部分的參數調整值(參考v$db_cache_advice、v$shared_pool_advice),關于pga也有相關視圖v$pga_target_advice 等。

data buffer
9i 中保留了8i中的參數,如設置了新的參數,則忽略舊的參數。9i中用db_cache_size來取代db_block_buffers , 用db_keep_cache_size 取代buffer_pool_keep, 用db_recycle_cache_size 取代buffer_pool_recycle;這里要注意9i 中設置的是實際的緩存大小而不再是塊的數量。另外9i新增加了db_nk_cache_size,這是為了支持在同一個數據庫中使用不同的塊大小而設置的。對于不同的表空間,可以定義不同的數據塊的大小,而緩沖區的定義則依靠該參數的支持。其中n 可以為2、4、6、8、16 等不同的值。在這里順便提及的一個參數就是db_block_lru_latches,該參數在9i中已經成為了保留參數,不推薦手工設置。

pga
在9i 里面這部分也有了很大的變化。在獨立模式下,9i已經不再主張使用原來的uga相關的參數設置,而代之以新的參數。假如workarea_size_policy=auto(缺省),則所有的會話的uga 共用一大塊內存,該內存由 pga_aggregate_target 設置。在我們根據前面介紹的方法評估了所有進程可能使用的最大pga 內存之后,我們可以通過在初始化參數中設置這個參數,從而不再關心其他 ”*_area_size” 參數。

sga_max_size
在9i中若設置了sga_max_size,則在總和小于等于這個值內,可以動態的調整數據緩沖區和共享池的大小
sql> show parameters sga_max_size
name       type             value
---------------- -------------------- ------- -------------
sga_max_size  unknown         193752940
sql>
sql> alter system set db_cache_size = 30000000;
system altered.
sql> alter system set shared_pool_size = 20480000;
system altered.


1.5  lock_sga = true 的問題
由于幾乎所有的操作系統都支持虛擬內存,所以即使我們使用的內存小于物理內存,也不能避免操作系統將sga 換到虛擬內存(swap)。所以我們可以嘗試使得sga 鎖定在物理內存中不被換到虛擬內存中,這樣減少頁面的換入和換出,從而提高性能。但在這里遺憾的是,windows 是無法避免這種情況的。下面我們來參考在不同的幾個系統下怎么實現lock_sga
aix 5l(aix 4.3.3 以上)
logon aix as root
cd /usr/samples/kernel
./vmtune (信息如下) v_pingshm已經是1
./vmtune -s 1
然后oracle用戶修改initsid.ora 中 lock_sga = true
重新啟動數據庫

hp unix
root身份登陸
create the file "/etc/privgroup": vi /etc/privgroup
add line "dba mlock" to file
as root, run the command "/etc/setprivgrp -f /etc/privgroup":
$/etc/setprivgrp -f /etc/privgroup
oracle用戶修改initsid.ora中lock_sga=true
重新啟動數據庫

solaris (solaris2.6以上)
8i版本以上數據庫默認使用隱藏參數 use_ism = true ,自動鎖定sga于內存中,不用設置lock_sga, 如果設置 lock_sga =true 使用非 root 用戶啟動數據庫將返回錯誤。

windows
不能設置lock_sga=true,可以通過設置pre_page_sga=true,使得數據庫啟動的時候就把所有內存頁裝載,這樣可能起到一定的作用。


2.  應用優化
下面我們從技術的角度入手,來探討數據庫優化方面的問題。通常作為優化oracle系統的人,或者是dba,其實很多時候對應用并不很了解甚至可以說是完全不了解,更不要說對應用程序代碼的了解。事實上呢,一個系統運行的快或者慢相信大家都明白,第一重要的是數據庫的設計,然后是應用的設計,sql語句的編寫,最后才是數據庫參數的調整和硬件、網絡的問題,等等。所以在我們不了解一個系統的時候來優化數據庫應用不是一個輕松的容易的事情。那么我們第一步應該怎么做呢?
通常有兩類方法:
其中一個方法就是我們常用的,使用statspack來進行診斷系統的瓶頸所在。在statspack中oracle給出了幾乎涵蓋oracle大部分重要內容的信息。
另外一種方式,就是trace session。假如某個session運行很慢或者某個用戶的某個查詢很慢,那么這個時候我們可以通過trace session的方式來診斷到底是慢在哪里,看究竟執行計劃是怎樣的,然后在user_dump_dest下根據該session的進程號或者線程號可以找到一個產生的trace文件。通過使用tkprof格式化文件之后我們就可以看見很多的統計信息,這里包括了執行計劃、parse/fetch等步驟消耗cpu的時間。通常我們是觀察query模式下的consistent gets來首先看sql是否使用了索引,然后看執行計劃是不是正常,是不是有調整的余地。當然如果您沒有實際做過的話,這些內容說起來很抽象。這是在不了解應用和程序下針對特定session的診斷和調整過程。
trace session的方式是一種自下而上的方法,從sql入手;而statspack是自頂向下的方法,也就是從宏觀上先診斷數據庫的瓶頸在哪里,然后從瓶頸入手來做調整,這個習慣上又可以稱為通過等待事件(wait event)入手的方法。

2.1  使用statspack
statspack是一個性能診斷工具,首先發布于oracle8.1.6版本,在8.1.7版本中功能得到加強。statspack除了查找實例中的性能問題外,還可以查找應用程序中高負荷的sql語句,很容易確定oracle 數據庫的瓶頸所在,并且記錄數據庫性能狀態。
在數據庫中statspack 的腳本位于$oracle_home/rdbms/admin 目錄下,對于oracle8.1.6,是一組以stat 開頭的文件;對于oracle8.1.7,是一組以sp 開頭的文件。
在statspack 發布之前,我們通常能夠使用診斷數據庫的工具是兩個腳本utlbstat.sql 和utlestat.sql,bstat/estat 是一個非常簡單的性能診斷工具。utlbstat 獲得開始時很多v$視圖的快照,utlestat 通過先前的快照和當前視圖生成一個報表。
該報表實際上相當于statspack 中的兩個采樣點。
statspack 通過連續的采樣,能夠給我們提供至關重要的趨勢分析數據。這是一個巨大的進步。能夠使用statspack 的環境我們就盡量不要使用bstat/estat 的方式來診斷數據庫問題。

2.1.1  安裝statapack
§ 步驟一:
為了能夠順利安裝和運行statspack ,首先需要設置以下兩個系統參數:
1.  job_queue_processes
為了能夠建立自動任務,執行數據收集,該參數需要大于0。你可以在初試化參數文件中修改該參數(使該參數在重起后以然有效)。
該參數可以在系統級動態修改(重起后失效)。

sql> alter system set job_queue_processes = 6;
system altered

在oracle9i 當中,可以指定范圍,如 both,這樣該修改在當前及之后保持有效(僅當你使用spfile 時,如果在9i 中仍然使用pfile,那么更改方法同8i 相同):

sql> alter system set job_queue_processes = 6 scope=both;
system altered


2.  timed_statistics
收集操作系統的計時信息,這些信息可被用來顯示時間等統計信息、優化數據庫和 sql 語句。要防止因從操作系統請求時間而引起的開銷,請將該值設置為false。
使用statspack 收集統計信息時建議將該值設置為 true,否則收集的統計信息大約只能起到10%的作用,將timed_statistics 設置為true 所帶來的性能影響與好處相比是微不足道的。
該參數使收集的時間信息存儲在在v$sesstats 和v$sysstats 等動態性能視圖中。
timed_statistics 參數也可以在實例級進行更改

sql> alter system set timed_statistics = true;
system altered

如果你擔心一直啟用timed_statistics 對于性能的影響,你可以在使用statspack 之前在system 更改,采樣過后把該參數動態修改成false。

§ 步驟二:
需要單獨為statspack創建一個存儲數據的表空間,如果采樣間隔較短,周期較長,打算長期使用,那么可能需要一個大一點的表空間,如果每個半個小時采樣一次,連續采樣一周,數據量是很大的。下面的例子中創建了一個500m 的測試表空間。
注意: 這里創建的表空間不能太小,如果太小的話創建對象會失敗,建議至少建立100m 表空間。

sql> create tablespace perfstat
2 datafile '/oracle/oradata/oradata/res/perfstat.dbf'
3 size 500m;
tablespace created。

§ 步驟三:
在 sqlplus 中用internal 身份登陸,或者擁有sysdba(connect / as sysdba)權限的用戶登陸。
注: 在oracle9i 中,不存在internal 用戶,可以使用sys 用戶以sysdba 身份連接。
先轉到$oracle_home/rdbms/admin 目錄,檢查安裝腳本是否存在,同時我們執行腳本也可以方便些。

$ cd $oracle_home/rdbms/admin
$ ls -l sp*.sql
-rw-r--r--   1 oracle   other       1774 feb 18  2000 spauto.sql
-rw-r--r--   1 oracle   other      62545 jun 15  2000 spcpkg.sql
-rw-r--r--   1 oracle   other        877 feb 18  2000 spcreate.sql
-rw-r--r--   1 oracle   other      31193 jun 15  2000 spctab.sql
-rw-r--r--   1 oracle   other       6414 jun 15  2000 spcusr.sql
-rw-r--r--   1 oracle   other        758 jun 15  2000 spdrop.sql
-rw-r--r--   1 oracle   other       3615 jun 15  2000 spdtab.sql
-rw-r--r--   1 oracle   other       1274 jun 15  2000 spdusr.sql
-rw-r--r--   1 oracle   other       6760 jun 15  2000 sppurge.sql
-rw-r--r--   1 oracle   other      71034 jul 12  2000 spreport.sql
-rw-r--r--   1 oracle   other       2191 jun 15  2000 sptrunc.sql
-rw-r--r--   1 oracle   other      30133 jun 15  2000 spup816.sql
$

接下來我們就可以開始安裝statspack 了。在oracle8.1.6 版本中運行statscre.sql; 在oracle8.1.7 版本中運行spcreate.sql。
這期間會提示你輸入缺省表空間和臨時表空間的位置,輸入我們為 perfstat 用戶創建的表空間和你的臨時表空間。安裝腳本會自動創建perfstat 用戶。

$ sqlplus

sql*plus: release 8.1.7.0.0 - production on sat jul 26 16:27:31 2003

(c) copyright 2000 oracle corporation.  all rights reserved.

enter user-name: internal

connected to:
oracle8i enterprise edition release 8.1.7.0.0 - production
with the partitioning option
jserver release 8.1.7.0.0 - production

sql>
sql> @spcreate
... installing required packages

package created.

grant succeeded.

view created.

package body created.

package created.

synonym dropped.

synonym created.
……

specify perfstat user's default   tablespace
enter value for default_tablespace: perfstat
using perfstat for the default tablespace

user altered.

user altered.

specify perfstat user's temporary tablespace
enter value for temporary_tablespace: temp
using temp for the temporary tablespace

user altered.

note:
spcusr complete. please check spcusr.lis for any errors.

……

如果安裝成功,你可以接著看到如下的輸出信息:
….
creating package statspack...

package created.

no errors.
creating package body statspack...

package body created.

no errors.

note:
spcpkg complete. please check spcpkg.lis for any errors.

可以查看.lis 文件查看安裝時的錯誤信息。

§ 步驟四:
如果安裝過程中出現錯誤,那么可以運行spdrop.sql 腳本來刪除這些安裝腳本建立的對象。然后重新運行spcreate.sql來創建這些對象。

sql> @spdrop
dropping old versions (if any)

synonym dropped.

sequence dropped.

synonym dropped.

table dropped.

synonym dropped.

view dropped.
……
note:
spdusr complete. please check spdusr.lis for any errors.

(以上的安裝過程描述是在 hp 11.11 + oracle 8.1.7 平臺上得到的)

2.1.2  測試statspack
運行statspack.snap 可以產生系統快照,運行兩次,然后執行spreport.sql 就可以生成一個基于兩個時間點的報告。
如果一切正常,說明安裝成功。

sql>execute statspack.snap
pl/sql procedure successfully completed.
sql>execute statspack.snap
pl/sql procedure successfully completed.
sql>@spreport.sql

可是有可能你會得到以下錯誤:

sql> exec statspack.snap;
begin statspack.snap; end;
*
error at line 1:
ora-01401: inserted value too large for column
ora-06512: at "perfstat.statspack", line 978
ora-06512: at "perfstat.statspack", line 1612
ora-06512: at "perfstat.statspack", line 71
ora-06512: at line 1

這是oracle 的一個bug,bug 號1940915。
該bug 自8.1.7.3 后修正。
這個問題只會出現在多位的字符集, 需要修改spcpkg.sql 腳本,$oracle_home/rdbms/admin/spcpkg.sql,將"substr" 修改為 "substrb",然后重新運行該腳本。
該腳本錯誤部分:
select l_snap_id
, p_dbid
, p_instance_number
, substr(sql_text,1,31)
...........
substr 會將多位的字符, 當作一個byte.substrb 則會當作多個byte。在收集數據時, statpack 會將 top10 的 sql 前 31 個字節 存入數據表中,若在sql 的前31 個字有中文,就會出現此錯誤。
注意:運行 spcpkg.sql 也需要以 internal 用戶登錄 sqlplus


2.1.3  生成statspack報告
調用spreport.sql 可以生成分析報告:
當調用spreprot.sql 時,系統首先會查詢快照列表,然后要求你選擇生成報告的開始快照id(begin_snap)和結束快照id(end_snap),生成一個報告.
為了生成一個report,我們至少需要兩次采樣:


sql> @spreport  

   db id    db name      inst num instance
-----------   ------------       -------- ------------
  2749170756 res              1      res

completed snapshots

                           snap                    snap
instance     db name         id   snap started    level comment
------------ ------------ ----- ----------------- ----- ----------------------
res          res              1 26 jul 2003 16:36     5
                              2 26 jul 2003 16:37     5
                              3 26 jul 2003 17:03     5


specify the begin and end snapshot ids
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enter value for begin_snap:2
begin snapshot id specified: 2

enter value for end_snap: 3
end   snapshot id specified: 3


specify the report name
~~~~~~~~~~~~~~~~~~~~~~~
the default report file name is sp_2_3.  to use this name,
press to continue, otherwise enter an alternative.
enter value for report_name: rep0726.txt  

 ……

 end of report


在運行 spreport.sql 生成 statspack 報告的過程中,會有三個地方提示用戶輸入:
1、 開始快照id;
2、 結束快照id;
3、 輸出報告文件的文件名,缺省的文件名是sp__
上面輸入的開始快照id是2,開始快照id是3,輸出報告文件的文件名是rep0726.txt
成功運行一次 statspack.snap 就會產生一個 snapshot ,在生成 statspack 報告的時候就可以看到這個 snap id 和 snap 運行的時間。運行 statspack.snap ,就是上面所說的采樣,statspack 報告是分析兩個采樣點之間各種情況。

2.1.4  刪除歷史快照數據
前面講過,成功運行一次 statspack.snap 就會產生一個 snapshot ,這個 snapshot 的基本信息是存放在 perfstat.stats$snapshot 表中的,生成 statspack報告時會查詢該表的數據,供用戶選擇準備分析的 snapshot 。如果運行 statspack.snap 次數多了以后,該表的數據也會增加,歷史數據會影響正常運行的效果,因此需要定時清理一下歷史快照數據。
刪除stats$snapshot 數據表中的相應數據,其他表中的數據會相應的級連刪除:

sql> select max(snap_id) from stats$snapshot;
max(snap_id)
------------
166

sql> delete from stats$snapshot where snap_id < = 166;
143 rows deleted

你可以更改snap_id 的范圍以保留你需要的數據。
在以上刪除過程中,你可以看到所有相關的表都被鎖定。
sql> select a.object_id,a.oracle_username ,b.object_name
from v$locked_object a,dba_objects b
where a.object_id = b.object_id
/
object_id oracle_username object_name
------------------------------------- --------------------------------------------------------------------------------
156 perfstat snap$
39700 perfstat stats$librarycache
39706 perfstat stats$rollstat
39712 perfstat stats$sga
39754 perfstat stats$parameter
39745 perfstat stats$sql_statistics
39739 perfstat stats$sql_summary
39736 perfstat stats$enqueuestat
39733 perfstat stats$waitstat
39730 perfstat stats$bg_event_summary
39724 perfstat stats$system_event
39718 perfstat stats$sysstat
39715 perfstat stats$sgastat
39709 perfstat stats$rowcache_summary
39703 perfstat stats$buffer_pool_statistics
39697 perfstat stats$latch_misses_summary
39679 perfstat stats$snapshot
39682 perfstat stats$filestatxs
39688 perfstat stats$latch
174 perfstat job$
20 rows selected

oracle 還提供了系統腳本用于truncate 這些統計信息表,這個腳本名字是: sptrunc.sql (8i、9i 都相同)
該腳本主要內容如下,里面看到的就是statspack 相關的所有系統表:
truncate table stats$filestatxs;
truncate table stats$latch;
truncate table stats$latch_children;
truncate table stats$latch_misses_summary;
truncate table stats$latch_parent;
truncate table stats$librarycache;
truncate table stats$buffer_pool_statistics;
truncate table stats$rollstat;
truncate table stats$rowcache_summary;
truncate table stats$sga;
truncate table stats$sgastat;
truncate table stats$sysstat;
truncate table stats$sesstat;
truncate table stats$system_event;
truncate table stats$session_event;
truncate table stats$bg_event_summary;
truncate table stats$waitstat;
truncate table stats$enqueuestat;
truncate table stats$sql_summary;
truncate table stats$sql_statistics;
truncate table stats$sqltext;
truncate table stats$parameter;
delete from stats$snapshot;
delete from stats$database_instance;
commit;

2.1.5  一些重要腳本
1.通過導出保存及共享數據
在診斷系統問題時,可能需要向專業人士提供原始數據,這時我們可以導出statspack 表數據,
其中我們可能用到:spuexp.par
其內容主要為:
file=spuexp.dmp log=spuexp.log compress=y grants=y indexes=y rows=y constraints=y owner=perfstat consistent=y
我們可以導出如下:
exp userid=perfstat/my_perfstat_password parfile=spuexp.par

2.刪除數據
spdrop.sql 在執行時主要調用兩個腳本: spdtab.sql 、spdusr.sql
前者刪除表及同義詞等數據,后者刪除用戶

3.oracle92 中新增加的腳本
1) 用于升級statspack 對象的腳本,這些腳本需要以具有sysdba 權限的用戶運行, 升級前請先
備份存在的schema 數據:
spup90.sql: 用于升級9.0 版本的模式至9.2 版本。
spup817.sql: 如果從statspack 8.1.7 升級,需要運行這個腳本
spup816.sql: 從statspack 8.1.6 升級,需要運行這個腳本,然后運行spup817.sql
2) sprepsql.sql 用于根據給定的sql hash 值生成sql 報告


2.1.6  調整statspack的收集門限
statspack 有兩種類型的收集選項:

1.級別(level):控制收集數據的類型
statspack 共有三種快照級別,默認值是5
a. level 0: 一般性能統計。包括等待事件、系統事件、系統統計、回滾段統計、行緩存、sga、會話、鎖、緩沖池統計等等。
b. level 5: 增加sql 語句。除了包括level0 的所有內容,還包括sql 語句的收集,收集結果記錄在stats$sql_summary 中。
c. level 10: 增加子鎖存統計。包括level5 的所有內容。并且還會將附加的子鎖存存入stats$lathc_children 中。在使用這個級別時需要慎重,建議在oracle support 的指導下進行。
可以通過statspack 包修改缺省的級別設置
sql>execute statspack.snap(i_snap_level=>0,i_modify_parameter=>’true’);
通過這樣的設置,以后的收集級別都將是0 級。
如果你只是想本次改變收集級別,可以忽略i_modify_parameter 參數。
sql>execute statspack.snap(i_snap_level=>10);

2.快照門限:設置收集的數據的閾值。
快照門限只應用于stats$sql_summary 表中獲取的sql 語句。
因為每一個快照都會收集很多數據,每一行都代表獲取快照時數據庫中的一個sql 語句,所以stats$sql_summary 很快就會成為statspack 中最大的表。
門限存儲在stats$statspack_parameter 表中。讓我們了結一下各種門限:
a. executions_th 這是sql 語句執行的數量(默認值是100)
b. disk_reads_tn 這是sql 語句執行的磁盤讀入數量(默認值是1000)
c. parse_calls_th 這是sql 語句執行的解析調用的數量(默認值是1000)
d. buffer_gets_th 這是sql 語句執行的緩沖區獲取的數量(默認值是10000)
任何一個門限值超過以上參數就會產生一條記錄。
通過調用statspack.modify_statspack_parameter 函數我們可以改變門限的默認值。
例如:
sql>execute statspack.modify_statspack_parameter(i_buffer_gets_th=>100000,i_disk_reads_th=>100000;

2.2  對statspack報告的分析
從上面的描述可以看出,產生一個statspack報告是比較簡單的,但是如何讀懂statspack報告卻不是那么容易,需要對oracle的體系架構、內存結構、等待事件以及應用系統有充分的了解,加上不斷的實踐,才能基本讀懂statspack報告并且從報告中找到調整優化oracle的途徑。
下面接合一個實際的statspack報告,大致分析一下。

2.2.1  基本信息分析
db name         db id    instance     inst num release     ops host
------------ ----------- ------------ --------          ----------- ---      ---------  ---
res           2749170756 res                 1  8.1.7.0.0   no  res

                snap id     snap time      sessions
                ------- ------------------ --------
 begin snap:          2 26-jul-03 16:37:08       38
   end snap:          3 26-jul-03 17:03:23       38
    elapsed:                  26.25 (mins)

statspack報告首先描述了數據庫的基本情況,比如數據庫名、實例名、實例個數、oracle版本號等等;然后是該報告的開始快照和結束快照的信息,包括 snap id , snap time 等等;最后是該報告經過的時間跨度,單位是分鐘(mins)。

cache sizes
~~~~~~~~~~~
db_block_buffers:      61440          log_buffer:     163840
db_block_size:         8192     shared_pool_size:   52428800

然后描述了oracle內存結構中幾個重要的參數。

2.2.2  內存信息分析
load profile
~~~~~~~~~~~~                       per second       per transaction
                                   ---------------       ---------------
              redo size:              4,834.87             11,116.67
          logical reads:                405.53                932.43
          block changes:                 60.03                138.02
          physical reads:                138.63                318.75
          physical writes:                 54.27                124.79
          user calls:                     62.69                144.13
          parses:                        19.14                 44.00
          hard parses:                    2.26                  5.20
                  sorts:                  1.83                  4.20
                 logons:                  0.21                  0.47
               executes:                 21.10                 48.50
            transactions:                  0.43

  % blocks changed per read:   14.80    recursive call %:   34.45
 rollback per transaction %:    0.00       rows per sort:   20.57

redo size: 是日志的生成量,分為每秒和每事務所產生的,通常在很繁忙的系統中日志生成量可能達到上百k,甚至幾百k;

logical reads: 邏輯讀實際上就是logical io=buffer gets表示的含義,我們可以這樣認為,block在內存中,我們每一次讀一塊內存,就相當于一次邏輯讀;

parses 和 hard parses:  parse 和 hard parse通常是很容易出問題的部分,80%的系統的慢都是由于這個原因所導致的。
所謂parse分soft parse 和hard parse,soft parse是當一條sql傳進來后,需要在shared pool中找是否有相同的sql,如果找到了,那就是soft parse,如果沒有找著,那就開始hard parse,實際上hard parse主要是檢查該sql所涉及到的所有的對象是否有效以及權限等關系,hard parse之后才根據rule/cost模式生成執行計劃,再執行sql。
而hard parse的根源,基本都是由于不使用bind var所導致的,不使用bind var違背了oracle的shared pool的設計的原則,違背了這個設計用來共享的思想,這樣導致shared_pool_size里面命中率下降。因此不使用bind var,將導致cpu使用率的問題,極有使得性能急劇下降。
還有就是為了維護internal structure,需要使用latch,latch是一種oracle低級結構,用于保護內存資源,是一種內部生命周期很短的lock,大量使用latch將消耗大量的cpu資源。

sorts: 表示排序的數量;

executes: 表示執行次數;

transactions: 表示事務數量;

rollback per transaction %: 表示數據庫中事務的回退率。如果不是因為業務本身的原因,通常應該小于10%為好,回退是一個很消耗資源的操作。


instance efficiency percentages (target 100%)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           buffer nowait %:  100.00       redo nowait %:   99.98
           buffer  hit   %:   65.82    in-memory sort %:   99.65
           library hit   %:   91.32        soft parse %:   88.18
         execute to parse %:    9.28         latch hit %:   99.99
parse cpu to parse elapsd %:   94.61     % non-parse cpu:   99.90

buffer hit %: 數據緩沖區命中率,通常應該大于90%;

library hit %: libaray cache的命中率,通常應該大于98%;

in-memory sort %: 排序在內存的比例,如果這個比例過小,可以考慮增大sort_area_size,使得排序在內存中進行而不是在temp表空間中進行;

soft parse %: 軟解析的百分比,這個百分比也應該很大才好,因為我們要盡量減少hard parse。 soft parse 百分比=soft/(soft+hard);

execute to parse %: 這個數字也應該是越大越好,接近100%最好。有些報告中這個值是負的,看上去很奇怪。事實上這表示一個問題,sql如果被age out的話就可能出現這種情況,也就是sql老化,或執行alter system flush shared_pool等。


shared pool statistics          begin   end
                             ------   ------
         memory usage %:    90.63   87.19
   % sql with executions>1:   71.53   75.39
 % memory for sql w/exec>1:  59.45   65.17

% sql with executions>1: 這個表示sql被執行次數多于一次的比率,也應該大為好,小則表示很多sql只被執行了一次,說明沒有使用bind var;

2.2.3  等待事件分析
接下來,statspack報告中描述的是等待事件(wait events),這是oracle中比較復雜難懂的概念。
oracle 的等待事件是衡量oracle 運行狀況的重要依據及指標。
等待事件的概念是在oracle7.0.1.2 中引入的,大致有100 個等待事件。在oracle 8.0 中這個數目增加到了大約150 個,在oracle8i 中大約有200 個事件,在oracle9i 中大約有360 個等待事件。
主要有兩種類別的等待事件,即空閑(idle)等待事件和非空閑(non-idle)等待事件。
空閑事件指oracle 正等待某種工作,在診斷和優化數據庫的時候,我們不用過多注意這部分事件。
常見的空閑事件有:
? dispatcher timer
? lock element cleanup
? null event
? parallel query dequeue wait
? parallel query idle wait - slaves
? pipe get
? pl/sql lock timer
? pmon timer- pmon
? rdbms ipc message
? slave wait
? smon timer
? sql*net break/reset to client
? sql*net message from client
? sql*net message to client
? sql*net more data to client
? virtual circuit status
? client message

非空閑等待事件專門針對oracle 的活動,指數據庫任務或應用運行過程中發生的等待,這些等待事件是我們在調整數據庫的時候應該關注與研究的。
一些常見的非空閑等待事件有:
? db file scattered read
? db file sequential read
? buffer busy waits
? free buffer waits
? enqueue
? latch free
? log file parallel write
? log file sync

下面接合statspack中的一些等待事件進行講述。

top 5 wait events
~~~~~~~~~~~~~~~~~                              wait     % total
event                                    waits  time (cs)   wt time
--------------------------------------------           ------------ ------------    -------
db file scattered read                      26,877       12,850   52.94
db file parallel write                         472        3,674   15.13
log file parallel write                         975        1,560    6.43
direct path write                           1,571        1,543    6.36
control file parallel write                     652        1,290    5.31
          -------------------------------------------------------------

db file scattered read: db文件分散讀取。這個等待事件很常見,經常在top5中出現,這表示,一次從磁盤讀數據進來的時候讀了多于一個block的數據,而這些數據又被分散的放在不連續的內存塊中,因為一次讀進來的是多于一個block的。
通常來說我們可以認為是全表掃描類型的讀,因為根據索引讀表數據的話一次只讀一個block,如果這個數字過大,就表明該表找不到索引,或者只能找到有限的索引,可能是全表掃描過多,需要檢查sql是否合理的利用了索引,或者是否需要建立合理的索引。
當全表掃描被限制在內存時,它們很少會進入連續的緩沖區內,而是分散于整個緩沖存儲器中。盡管在特定條件下執行全表掃描可能比索引掃描更有效,但如果出現這種等待時,最好檢查一下這些全表掃描是否必要,是否可以通過建立合適的索引來減少對于大表全表掃描所產生的大規模數據讀取。
對于經常使用的小表,應該盡量把他們pin 在內存中,避免不必要的老化清除及重復讀取。

db file sequential read: db文件連續讀取。通常顯示單個塊的讀取(通常指索引讀取),表示的是讀進磁盤的block被放在連續的內存塊中。
事實上大部分基本代表著單個block的讀入,可以說象征著 io 或者說通過索引讀入的比較多 。因為一次io若讀進多個的block,放入連續的內存塊的幾率是很小的,分布在不同block的大量記錄被讀入就會遇到此事件。因為根據索引讀數據的話,假設100條記錄,根據索引,不算索引本身的讀,而根據索引每個值去讀一下表數據,理論上最多可能產生100 buffer gets,而如果是full table scan,則100條數據完全可能在一個block里面,則幾乎一次就讀過這個block了,就會產生這么大的差異。
這種等待的數目很多時,可能顯示表的連接順序不佳,或者不加選擇地進行索引。
對于高級事務處理(high-transaction)、調整良好(welltuned)的系統,這一數值很大是很正常的,但在某些情況下,它可能暗示著系統中存在問題。
你應當將這一等待統計量與statspack 報告中的已知問題(如效率較低的sql)聯系起來。檢查索引掃描,以保證每個掃描都是必要的,并檢查多表連接的連接順序。
db_cache_size 也是這些等待出現頻率的決定因素。有問題的散列區域(hash-area)連接應當出現在pga 內存中,但它們也會消耗大量內存,從而在順序讀取時導致大量等待。它們也可能以直接路徑讀/寫等待的形式出現。

free buffer wait: 釋放緩沖區。
這種等待表明系統正在等待內存中的緩沖,因為內存中已經沒有可用的緩沖空間了。如果所有sql 都得到了調優,這種等待可能表示你需要增大db_buffer_cache。釋放緩沖區等待也可能表示不加選擇的sql 導致數據溢出了帶有索引塊的緩沖存儲器,沒有為等待系統處理的特定語句留有緩沖區。
這種情況通常表示正在執行相當多數量的dml(插入/更新/刪除),并且可能說明dbwr 寫的速度不夠快,緩沖存儲器可能充滿了相同緩沖器的多個版本,從而導致效率非常低。為了解決這個問題,可能需要考慮增加檢查點、利用更多的dbwr 進程,或者增加物理磁盤的數量。

buffer busy wait: 緩沖區忙。
該等待事件表示正在等待一個以unshareable方式使用的緩沖區,或者表示當前正在被讀入buffer cache。也就是當進程想獲取或者操作某個block的時候卻發現被別的進程在使用而出現等待。一般來說buffer busy wait不應大于1%。
檢查緩沖等待統計部分(或v$waitstat),看一下等待是否位于段頭。如果是,可以考慮增加自由列表(freelist,對于oracle8i dmt)或者增加freelist groups.
其修改語法為:
sql> alter table sp_item storage (freelists 2);
table altered。

對于oracle8i而言,增加freelist參數,在很多時候可以明顯緩解等待,如果使用lmt,也就是local manangement tablespace,區段的管理就相對簡單還可以考慮修改數據塊的pctused/pctfree值,比如增大pctfree可以擴大數據的分布,在某種程度上就可以減少熱點塊的競爭。

如果這一等待位于undo header,可以通過增加回滾段(rollback segment)來解決緩沖區的問題。
如果等待位于undo block上,我們可能需要檢查相關應用,適當減少大規模的一致性讀取,或者降低一致性讀取(consistent read)的表中的數據密度或者增大db_cache_size。
如果等待處于data block,可以考慮將頻繁并發訪問的表或數據移到另一數據塊或者進行更大范圍的分布(可以增加pctfree 值 ,擴大數據分布,減少競爭),以避開這個"熱點"數據塊,或者可以考慮增加表中的自由列表或使用本地化管理的表空間(locally managed tablespaces)。
如果等待處于索引塊,應該考慮重建索引、分割索引或使用反向鍵索引。反向鍵索引在很多情況下,可以極大地緩解競爭,其原理有點類似于hash分區的功效。反向鍵索引(reverse key index)常建在一些值是連續增長的列上,例如列中的值是由sequence產生的。

為了防止與數據塊相關的緩沖忙等待,也可以使用較小的塊:在這種情況下,單個塊中的記錄就較少,所以這個塊就不是那么"繁忙";或者可以設置更大的pctfree,使數據擴大物理分布,減少記錄間的熱點競爭。
在執行dml (insert/update/ delete)時,oracle向數據塊中寫入信息,對于多事務并發訪問的數據表,關于itl的競爭和等待可能出現,為了減少這個等待,可以增加initrans,使用多個itl槽。
以下是一個生產系統v$waitstat 試圖所顯示的等待信息:
sql> select * from v$waitstat where count<>0 or time <>0;
class      count time
------------------ ---------- ----------
data block       453   6686
undo header      391   1126
undo block       172      3


latch free: latch釋放
latch 是一種低級排隊機制,用于保護sga 中共享內存結構。
latch就像是一種快速地被獲取和釋放的內存鎖。latch用于防止共享內存結構被多個用戶同時訪問。如果latch不可用,就會記錄latch釋放失敗(latch free miss)。
有兩種與閂有關的類型:
■ 立刻。
■ 可以等待。
假如一個進程試圖在立刻模式下獲得閂,而該閂已經被另外一個進程所持有,如果該閂不能立刻可用的話,那么該進程就不會為獲得該閂而等待。它將繼續執行另一個操作。
大多數latch 問題都與以下操作相關:
沒有很好的是用綁定變量(library cache latch)、重作生成問題(redo allocation latch)、緩沖存儲器競爭問題(cache buffers lru chain),以及buffer cache中的存在"熱點"塊(cache buffers chain)。
通常我們說,如果想設計一個失敗的系統,不考慮綁定變量,這一個條件就夠了,對于異構性極強的系統,不使用綁定變量的后果是極其嚴重的。
另外也有一些latch 等待與bug 有關,應當關注metalink 相關bug 的公布及補丁的發布。
當latch miss ratios大于0.5%時,就應當研究這一問題。
oracle 的 latch 機制是競爭,其處理類似于網絡里的csma/cd,所有用戶進程爭奪latch, 對于愿意等待類型(willing-to-wait)的latch,如果一個進程在第一次嘗試中沒有獲得latch,那么它會等待并且再嘗試一次,如果經過_spin_count 次爭奪不能獲得latch, 然后該進程轉入睡眠狀態,持續一段指定長度的時間,然后再次醒來,按順序重復以前的步驟.在8i/9i 中默認值是 _spin_count=2000。
如果sql語句不能調整,在8.1.6版本以上,oracle提供了一個新的初始化參數: cursor_sharing,可以通過設置cursor_sharing = force 在服務器端強制綁定變量。設置該參數可能會帶來一定的副作用,對于java的程序,有相關的bug,具體應用應該關注metalink的bug公告。


enqueue
enqueue 是一種保護共享資源的鎖定機制。該鎖定機制保護共享資源,如記錄中的數據,以避免兩個人在同一時間更新同一數據。enqueue 包括一個排隊機制,即fifo(先進先出)排隊機制。
enqueue 等待常見的有st、hw 、tx 、tm 等
st enqueue 用于空間管理和字典管理的表空間(dmt)的分配。對于支持lmt 的版本,可以考慮使用本地管理表空間,對于oracle8i,因為相關bug 不要把臨時表空間設置為lmt. 或者考慮預分配一定數量的區。
hw enqueue 指段的高水位標記相關等待;手動分配適當區段可以避免這一等待。
tx 是最常見的enqueue 等待。tx enqueue 等待通常是以下三個問題之一產生的結果。
第一個問題是唯一索引中的重復索引,你需要執行提交(commit)/回滾(rollback)操作來釋放enqueue。
第二個問題是對同一位圖索引段的多次更新。因為單個位圖段可能包含多個行地址(rowid),所以當多個用戶試圖更新同一段時,等待出現。直到提交或回滾, enqueue 釋放。
第三個問題,也是最可能發生的問題是多個用戶同時更新同一個塊。如果沒有自由的itl 槽,就會發生塊級鎖定。通過增大initrans 和/或maxtrans 以允許使用多個itl 槽,或者增大表上的pctfree值,就可以很輕松地避免這種情況。
tm enqueue 在dml 期間產生,以避免對受影響的對象使用ddl。如果有外鍵,一定要對它們進行索引,以避免這種常見的鎖定問題。


log buffer space: 日志緩沖空間
當你將日志緩沖(log buffer)產生重做日志的速度比lgwr 的寫出速度快,或者是當日志轉換(log switch)太慢時,就會發生這種等待。為解決這個問題,可以增大日志文件的大小,或者增加日志緩沖器的大小.
另外一個可能的原因是磁盤i/o 存在瓶頸,可以考慮使用寫入速度更快的磁盤。


log file switch (archiving needed)
這個等待事件出現時通常是因為日志組循環寫滿以后,第一個日志歸檔尚未完成,出現該等待可能是 io 存在問題。
解決辦法:
可以考慮增大日志文件和增加日志組
移動歸檔文件到快速磁盤
調整log_archive_max_processes .


log file switch (checkpoint incomplete): 日志切換(檢查點未完成)
當你的日志組都寫完以后,lgwr 試圖寫第一個log file,如果這時數據庫沒有完成寫出記錄在第一個log file 中的dirty 塊時(例如第一個檢查點未完成),該等待事件出現。
該等待事件說明你的日志組過少或者日志文件過小。
你可能需要增加你的日志組或日志文件大小。


log file switch: 日志文件轉換
所有的提交請求都需要等待"日志文件轉換(必要的歸檔)"或"日志文件轉換(chkpt.不完全)"。確保歸檔磁盤未滿,并且速度不太慢。dbwr 可能會因為輸入/輸出(i/o)操作而變得很慢。你可能需要增加更多或更大的重做日志,而且如果dbwxr 是問題癥結所在的話,可能需要增加數據庫書寫器。


log file sync: 日志文件同步
當一個用戶提交或回滾數據時,lgwr 將session 會話的重做由redo buffer 寫入到重做日志中。
log file sync 必須等待這一過程成功完成(oracle 通過寫redo log file 保證commit 成功的數據不丟失),這個事件說明提交可能過于頻繁,批量提交可以最大化lgwr 的效率,過分頻繁的提交會引起lgwr頻繁的激活,擴大了lgwr 的寫代價。
為了減少這種等待事件,可以嘗試每次提交更多的記錄。
將重做日志置于較快的磁盤上,或者交替使用不同物理磁盤上的重做日志,以降低歸檔對lgwr的影響。
對于軟raid,一般來說不要使用raid 5,raid5 對于頻繁寫入得系統會帶來較大的性能損失,可以考慮使用文件系統直接輸入/輸出,或者使用裸設備(raw device),這樣可以獲得寫入的性能提高。


log file single write
該事件僅與寫日志文件頭塊相關,通常發生在增加新的組成員和增進序列號時。頭塊寫單個進行,因為頭塊的部分信息是文件號,每個文件不同。更新日志文件頭這個操作在后臺完成,一般很少出現等待,無需太多關注。


log file parallel write
從log buffer 寫redo 記錄到redo log 文件,主要指常規寫操作(相對于log file sync)。
如果你的log group 存在多個組成員,當flush log buffer 時,寫操作是并行的,這時候此等待事件可能出現。
盡管這個寫操作并行處理,直到所有i/o 操作完成該寫操作才會完成(如果你的磁盤支持異步io或者使用io slave,那么即使只有一個redo log file member,也有可能出現此等待)。
這個參數和log file sync 時間相比較可以用來衡量log file 的寫入成本。通常稱為同步成本率。


control file parallel write: 控制文件并行寫
當server 進程更新所有控制文件時,這個事件可能出現。
如果等待很短,可以不用考慮。如果等待時間較長,檢查存放控制文件的物理磁盤i/o 是否存在瓶頸。
多個控制文件是完全相同的拷貝,用于鏡像以提高安全性。對于業務系統,多個控制文件應該存放在不同的磁盤上,一般來說三個是足夠的,如果只有兩個物理硬盤,那么兩個控制文件也是可以接受的。在同一個磁盤上保存多個控制文件是不具備實際意義的。
減少這個等待,可以考慮如下方法:
減少控制文件的個數(在確保安全的前提下)
如果系統支持,使用異步io
轉移控制文件到io 負擔輕的物理磁盤


control file sequential read/ control file single write
控制文件連續讀/控制文件單個寫
對單個控制文件i/o 存在問題時,這兩個事件會出現。
如果等待比較明顯,檢查單個控制文件,看存放位置是否存在i/o 瓶頸。
使用查詢獲得控制文件訪問狀態:
select p1 from v$session_wait
where event like 'control file%' and state='waiting';
解決辦法:
移動有問題的控制文件到快速磁盤
如果系統支持,啟用異步i/o


direct path wri, te: 直接路徑寫
該等待發生在,等待確認所有未完成的異步i/o 都已寫入磁盤。
你應該找到i/o 操作頻繁的數據文件,調整其性能。
也有可能存在較多的磁盤排序,臨時表空間操作頻繁,可以考慮使用local 管理表空間,分成多個小文件,寫入不同磁盤或者裸設備。


sql*net message from dblink
該等待通常指與分布式處理(從其他數據庫中select)有關的等待。
這個事件在通過dblinks 聯機訪問其他數據庫時產生。如果查找的數據多數是靜態的,可以考慮移動這些數據到本地表并根據需要刷新,通過快照或者物化視圖來減少跨數據庫的訪問,會在性能上得到很大的提高。


slave wait: 從屬進程等
slave wait 是slave i/o 進程等待請求,是一個空閑參數,一般不說明問題。

2.2.4  high load sql 分析
對于一個特定的應用程序或者系統來講,要調整優化其性能,最好的方法是檢查程序的代碼和用戶使用的sql語句。
如果使用了 level 5 級別的 snapshot ,那么statspack生成的報告中就會顯示系統中高負荷sql語句(high load sql)的信息,而其詳細信息可以在 stats$sql_summary 表中查到。缺省情況下 snapshot 的級別是 level 5。
按照 buffer gets, physical reads, executions, memory usage and version count 等參數的降序排列順序,把sql語句分為幾個部分羅列在報告中。

2.2.5  報告的其他部分
statspack報告的其他部分包括了 instance activity stats,tablespace io stats,buffer pool statistics,buffer wait statistics,rollback segment stats,latch activity,dictionary cache stats,library cache activity,sga breakdown difference 以及 init.ora 參數,等等。目前本文不對這些內容進行詳細討論,請參加其他詳細文檔。

2.3 trace session


2.4 基于成本的優化器技術內幕
oracle基于成本的優化器(oracle's cost-based sql optimizer ,簡稱cbo),是oracle里面非常復雜的一個部分, 它決定了oracle里面每個sql的執行路徑。cbo是一項評價sql語句和產生最好執行計劃的具有挑戰性的工作,所以也使它成oracle最復雜的軟件組成部分。
眾所周知,sql的執行計劃,幾乎是oracle性能調整最重要的方面了。所以想要學會如何調整oracle數據庫的性能,就要學會如何對sql進行調整,就需要深入透徹理解cbo。
cbo的執行路徑,取決于一些外部因素,內部的oracle統計數據,以及數據是如何分布的。
我們將要討論下面的話題:
cbo的參數:我們從基本的優化器參數開始學習,然后學習每個優化器參數是如何影響oracle的優化器的執行的。

cbo的統計:這里我們將討論,使用analyze或者dbms_stats來收集正確的統計數據,對oracle 優化器而言,是多么的重要。我們還將學習如何把優化器的統計數據,從一個系統拷貝到另外一個系統,這樣可以確保開發環境和產品數據庫環境下,sql的執行路徑不會變化。

下面我們開始討論cbo優化模式以及影響cbo的oracle參數

2.4.1  cbo的參數
cbo受一些重要參數的影響,修改這些參數后可以看到cbo性能上戲劇性的變化。首先從設置cbo的optimizer_mode參數開始,然后討論其他重要參數的設置。

在 oracle 9i 中,optimizer_mode 參數有四種取值,決定了四種優化模式: rule, choose, all_rows, 和 first_rows,其中 rule 和 choose 兩種模式表示目前已經過時的基于規則的優化器模式(rule-based optimizer,簡稱rbo),所以我們在此著重討論后兩種cbo模式。

優化模式的設置可以在系統級進行,也可以對某個會話(session)進行設置,或者對某個sql語句進行設置。對應的語句如下:
alter system set optimizer_mode=first_rows_10;
alter session set optimizer_goal = all_rows;
select /*+ first_rows(100) */ from student;

我們首先需要知道對一個sql語句來說,什么是最好的執行計劃(the best execution plan)?是使sql語句返回結果的速度最快,還是使sql語句占用系統資源最少?顯然,這個答案取決于數據庫的處理方式。

舉一個簡單的例子,比如有下列sql語句:
select customer_name
from
   customer
where
   region = 'south'
order by
   customer_name;

如果最好的執行計劃是返回結果的速度最快,那么就需要使用 region 列和 customer_name 列上的索引,從 customer 表中按照正確的順序快速讀取所有的列,而不用管是否從物理上讀取了很多不連續的數據塊導致的大量io操作。(見下圖)
 

假設這個執行計劃從開始到返回結果耗時 0.0001 秒,同時產生了 10000 個 db_block_gets ,但是如果你的目標是計算資源的最小化呢?如果這個sql語句是在一個批處理程序中執行,也許對返回結果的速度要求就不那么重要了,而另一個執行計劃則可能耗費更少的系統資源。
在下圖所示的例子中,并行的全表掃描由于不需要按照排序重新讀取數據塊,所以耗系統資源較少,并且io操作也不多。當然,由于sql語句執行過程中沒有排序,得到預期結果的時間就長了,而資源耗費少了。假設這個執行計劃從開始到返回結果耗時 10 秒,同時產生了 5000 個 db_block_gets
 

oracle提供了幾個 optimizer_mode 的設置參數,使你能夠得到想要的最好的執行計劃。

optimizer_mode = first_rows
設置為這種cbo模式以后,sql語句返回結果的速度會盡可能的快,而不管系統全部的查詢是否會耗時較長或者耗系統資源過多。由于利用索引會使查詢速度加快,所以 first_rows 優化模式會在全表掃描上進行索引掃描。這種優化模式一般適合于一些oltp系統,滿足用戶能夠在較短時間內看到較小查詢結果集的要求。

optimizer_mode = all_rows
設置為這種cbo模式以后,將保證消耗的所有計算資源最小,盡管有時查詢結束以后沒有結果返回。all_rows 的優化模式更傾向于全表掃描,而不是全索引掃描和利用索引排序,因此這種優化模式適合于數據查看實時性不是那么強的數據倉庫、決策支持系統和面向批處理的數據庫(batch-oriented databases)等。

optimizer_mode = first_rows_n
oracle 9i 對一些預期返回結果集的數據量小的sql語句優化模式進行了加強,增加了四個參數值:first_rows_1、first_rows_10、first_rows_100、first_rows_1000。cbo通過 first_rows_n 中的 n 值,決定了返回結果集數量的基數,我們可能僅僅需要查詢結果集中的一部分,cbo就根據這樣的 n 值來決定是否使用索引掃描。

optimizer_mode = rule
基于規則的優化器模式,rbo,是早期oracle版本使用過的一種優化模式。由于rbo不支持自1994年oracle版本的新特性,如 bitmap indexes,table partitions,function-based indexes等,所以在以后oracle版本中已經不再更新rbo,并且也不推薦用戶使用rbo這種優化模式了。

從上面的討論可以看出,optimizer_mode 參數的設置對cbo是非常重要的,決定了cbo的基本模式,同時還有一些其他的參數也對cbo有著極大的影響。由于cbo的重要性,oracle提供了一些系統級的參數來調整cbo的全局性能,這些調整參數包括索引掃描與全部掃描的選擇、表連接方式的選擇,等等。下面簡單討論一下。

optimizer_index_cost_adj
這個參數用于調整使用索引的訪問路徑的成本算法,參數值越小,索引訪問的成本就越低。

optimizer_index_caching
這個參數告訴oracle在內存緩沖區中索引的數量。該參數的設置會影響cbo如何決定使用表連接(嵌套循環)的索引還是使用全表掃描。

db_file_multiblock_read_count
這個參數的值被設置較大的時候,cbo就會認為離散的、多數據塊的讀取會比順序讀取的代價更低,使得cbo更傾向于全表掃描。

parallel_automatic_tuning
這個參數值被設置為 on 的時候,表示使用并行的全表掃描,由于并行的全表掃描比較快,所以cbo認為索引的訪問是高成本的,同時就更傾向于全表掃描。

hash_area_size
如果不使用 pga_aggregate_target 參數的話,該參數有效。該參數的設置大小決定cbo是否更加傾向于 hash joins ,而不是嵌套循環和表連接的索引合并。

sort_area_size
如果不使用 pga_aggregate_target 參數的話,該參數有效。該參數的設置大小影響cbo決定是否進行索引訪問和結果集的排序,參數值越大,在內存中排序的可能性就越大,cbo也就更加傾向于排序。

由于對這些參數值的修改會影響到系統中成千上萬的sql語句的執行計劃,所以oracle并不推薦修改這些參數的缺省值。

在對cbo的參數有了大致的了解以后,下面討論如何根據提供給cbo的數據幫助cbo制定出一個好的執行計劃。

2.4.2  cbo的統計
對于cbo來說,最重要的是定義和管理好你的統計數據,為了使cbo能夠為你的sql語句產生一個最好的執行計劃,必須要有與sql語句相關的表和索引統計數據。只有當cbo知道了相關的信息,如表的大小、分布、基數以及列值的可選性等,才能對sql語句作出正確的判斷,從而得到最好的執行計劃。

下面討論一下如何獲得高質量的cbo統計數據,如何為你的數據庫系統創建一個適當的cbo環境。

cbo產生最好執行計劃的能力來自于統計數據的有效性,獲得統計數據的比較過時的方法是 analyze table 和 dbms_utility ,這兩種方法對sql語句的性能有一些危害,因為我們知道,cbo是使用對象統計數據(object statistics)來為所有的sql語句選擇最好的執行計劃。
dbms_stats 應用功能包是產生統計數據較好的方法,特別對大型分區表而言。下面看一個使用 dbms_stats 的例子。
exec dbms_stats.gather_schema_stats(
  ownname          => 'scott',
  options            => 'gather auto',
  estimate_percent    => dbms_stats.auto_sample_size,
  method_opt        => 'for all columns size repeat',
  degree            => 34
   )


上面例子中的options參數的幾個可選值需要說明一下。
gather  重新分析整個schema,產生統計數據;

  gather empty 僅分析那些還沒有統計數據的表;

  gather stale 僅重新分析那些發生了10%變化的表(變化原因可能是 inserts, updates , deletes )

  gather auto 僅重新分析那些還沒有統計數據和發生了10%變化的表,該選項相當于 gather empty 和 gather stale 同時使用。


使用 gather auto 和 gather stale 兩個選項需要進行監控,如果你執行了 alter table xxx monitoring 命令,oracle利用 dba_tab_modifications 視圖跟蹤表的變化,記錄了最近一次統計數據分析以來的 insert , update , delete 的準確記錄數。
sql> desc dba_tab_modifications;
 name                     type
 -----------------              ---------------
 table_owner          varchar2(30)
 table_name           varchar2(30)
 partition_name       varchar2(30)
 subpartition_name   varchar2(30)
 inserts                 number
 updates                number
 deletes                number
 timestamp             date
 truncated             varchar2(3)

比較有趣的一個選項是 gather stale ,比如在一個數據更新頻繁的oltp系統中,幾乎所有的統計數據都會很快的過時,而我們必須記住 gather stale 選項是在表中10%的記錄發生變化時才對該表重新分析產生統計數據,因此除了只讀表以外的所有表幾乎使用 gather stale 選項重新分析產生統計數據,所以 gather stale 選項主要還是用于一些主要是只讀表組成的系統中。

在上面使用 dbms_stats 的例子中,我們看到了一個參數 estimate_percent ,它的值是 dbms_stats.auto_sample_size, 這個參數值是 oracle 9i 才開始使用的,這個參數值的出現極大方便了統計數據的分析產生。
我們知道,統計數據的質量越高,cbo產生最好執行計劃的能力就越強,但是由于數據庫統計采樣大小的問題,對一個大型數據庫系統做一個完整的統計數據分析產生將會耗時數天,最好的辦法就是在高質量的統計數據和數據庫統計采樣大小之間得到一個平衡點。
在早一些的oracle版本中,為了得到統計數據,dba不得不猜測一個最好的數據采樣大小百分比。但是從 oracle 9i 開始,可以通過 dbms_stats 包來自己指定 estimate_percent 參數的值了,那就是 dbms_stats.auto_sample_size
通過這種方式設置了自動采樣大小以后,我們可以通過下列數據字典視圖的 sample_size 字段來驗證這些自動產生的統計采樣大小。
dba_all_tables
dba_indexes
dba_ind_partitions
dba_ind_subpartitions
dba_object_tables
dba_part_col_statistics
dba_subpart_col_statistics
dba_tables
dba_tab_cols
dba_tab_columns
dba_tab_col_statistics
dba_tab_partitions
dba_tab_subpartitions

使用自動統計采樣以后,oracle會根據表的大小和列值的分布在5%到20%之間取值。記住:你的統計數據質量越高,cbo作出的決定就越對你有利。

現在我們對cbo統計數據應該有一些了解了,下面來看看在一個成功的oracle系統是如何管理cbo統計數據。

2.4.3  cbo的正確環境
成功使用cbo的關鍵是穩定性,下面是一些成功使用cbo的基本事項。

●只在必需的時候才進行統計數據的重新分析
oracle dba們最容易犯的一個普遍錯誤就是經常性的對系統的統計數據進行重新分析。記住:做這件事的唯一目的是改變sql語句的執行計劃,如果這個執行計劃沒有被破壞,就不要去修復它。如果你對sql語句的性能還滿意的話,重新分析產生統計數據以后可能會產生較大的性能問題,并給開發團隊帶來影響。實際運用中,也是極少數的oracle系統才會周期性的對統計數據進行重新分析。
一般來講,一個數據庫應用系統的基本架構是不會輕易改變,大數據量的表仍然是很大,索引列的分布、基數值等等也很少變化。只有下列幾種情況的數據庫才可能經常對整個系統的統計數據重新分析:
1、用于數據分析的數據庫
   有一些由于科學試驗數據分析的數據庫系統,經常會更換整個一套的試驗數據,那么這種情況下當數據庫重新load了一套數據以后,可以立即重新對統計數據進行分析。
2、高度變化的數據庫
   這是極少數的例子,表的大小或者索引列的數據在劇烈的變化,比如一張表有100條記錄,一周以后就變成10000條記錄。這種情況下也可以考慮周期性的進行統計數據分析。


●強迫開發人員調整自己的sql
很多開發人員錯誤的認為,他們的任務就是編寫sql語句然后從數據庫中獲得正確的數據。但是實際上編寫出sql語句只是開發人員一半的工作,在一個成功的oracle應用系統中,會要求開發人員的sql語句采用最優化的方式訪問數據庫,并且保證sql語句的執行計劃在新的sql之間的可移植性。
令人驚訝的是,在許多oracle應用系統中都不怎么考慮具體sql語句的執行計劃,認為cbo是很智能的,無論如何都可以為我們提供最好的sql語句執行計劃。
同一個查詢在sql語句中可能有不同方式的寫法,而每一種寫法都可能有不同的執行計劃。觀察下面的例子,每一個查詢的結果都是一樣的,但是執行計劃卻相去甚遠。

-- 使用了不正確的子查詢
select
  book_title
from
  book
where
  book_key not in (select book_key from sales);
 
execution plan
----------------------------------------------------------
0      select statement optimizer=choose (cost=1 card=1 bytes=64)
1    0   filter
2    1     table access (full) of 'book' (cost=1 card=1 bytes=64)
3    1     table access (full) of 'sales' (cost=1 card=5 bytes=25)


-- 使用了兩張表的外連接
select
  book_title
from
  book  b,
  sales  s
where
  b.book_key = s.book_key(+) 
and
  quantity is null;

execution plan
----------------------------------------------------------
0   select statement optimizer=choose (cost=3 card=100 bytes=8200)

1  0 filter
2  1   filter
3  2     hash join (outer)
4  3      table access (full) of 'book' (cost=1 card=20 bytes=1280)
5  3      table access (full) of 'sales' (cost=1 card=100 bytes=1800)


-- 使用了三個正確的子查詢
select
  book_title
from
  book
where
  book_title not in (
                select
                distinct
                  book_title
                from
                  book,
                  sales
                where
                  book.book_key = sales.book_key
                and
                  quantity > 0);

execution plan
----------------------------------------------------------
0   select statement optimizer=choose (cost=1 card=1 bytes=59)
1  0  filter
2  1   table access (full) of 'book' (cost=1 card=1 bytes=59)
3  1   filter
4  3     nested loops (cost=6 card=1 bytes=82)
5  4       table access (full) of 'sales' (cost=1 card=5 bytes=90)
6  4       table access (by index rowid) of 'book' (cost=1 card=1)
7  6         index (unique scan) of 'pk_book' (unique)

我們看到,正確的sql語句寫法產生的執行計劃是如此的不同。明智的開發人員知道如何去編寫能夠產生最好執行計劃的sql語句,明智的oracle應用系統也會主動訓練開發人員去編寫最有效的sql語句。

下面是一些幫助開發人員優化sql語句的技巧:
1、 使用 autotrace 和 tkprof 功能去分析sql語句的執行計劃;
2、 保證所有生產環境中的sql語句都是在測試環境中經過優化的;
3、 制定一個性能優化的標準,而不是只要求開發人員編寫出最快的sql語句。根據這種標準,好的開發人員應該能夠寫出最有效的sql語句。

●謹慎管理cbo統計數據
成功的oracle系統會謹慎管理他們的cbo統計數據,以保證cbo在測試環境和生產環境中以同樣的方式工作。一個聰明的dba會在得到高質量的cbo統計數據以后,把這些統計數據移植到測試環境中,這樣sql語句的執行計劃在測試環境和生產環境中就是一樣的了。

對dba來說,一個重要的工作就是收集和發布cbo統計數據,并隨時保持一套當前運行環境的最精確的統計數據。在一些情況下,可能會有不止一套的優化統計數據。比如,對oltp運行的最好的統計數據可能對數據倉庫運行卻不是最好的,在這種情況下,dba就需要保持兩套統計數據,并根據不同的運行條件導入系統。

可以使用 dbms_stats 包中的 export_system_stats 存儲過程來完成cbo統計數據的導出。下面的例子中,我們把當前cbo統計數據導出到一張名叫 stats_table_oltp的表中。
dbms_stats.export_system_stats(‘stats_table_oltp’)

導出以后,我們就可以把這張表拷貝到別的實例中,當系統的運行模式改變以后,使用 dbms_stats 包中的 import_system_stats 存儲過程來完成cbo統計數據的導入。
dbms_stats.import_system_stats(‘stats_table_oltp’)

●千萬不要隨便改動cbo參數的值
改動cbo相關參數的值是非常危險的,因為一個小小的改動可能就會對整個系統的執行性能帶來極大的負面影響,只有在經過嚴格的系統測試以后才能改動這些參數的值。可能帶來極大影響的參數值包括:optimizer_mode, optimizer_index_cost_adj, and optimizer_index_caching。而其他參數,比如 hash_area_size , sort_area_size, 參數值的改變就不是那么危險了,可以在會話級進行改變以幫助cbo優化查詢。

●保證靜態的執行計劃
成功的cbo應用會通過謹慎管理統計數據來鎖定sql執行計劃,同時保證存儲的優化計劃的穩定性,或者在具體的sql語句中加入一些細節上的提示。
記住:重新分析一個系統的統計數據,可能會導致成千上萬的sql語句改變其執行計劃。許多oracle應用系統要求所有的sql語句在測試環境中經過驗證,保證在功能上和生產環境是一致的。


2.4.4  cbo的思考
盡管我們已經對cbo的不少細節有了了解,但是由于隨著oracle新版本的不斷推出,cbo變得越來越強大,同時也越來越復雜,我們仍然有許多關于cbo的知識需要學習。
下面是一些關于cbo調整的提綱性的建議,供準備進行cbo調整的dba們思考。

●dba可以提供一些oracle參數的配置對cbo進行控制,但是只能在有限的環境下謹慎的改變這些參數;

●cbo依靠統計數據來產生sql語句的優化的執行計劃,可以通過 dbms_stats 包來分析、產生統計數據;

●dba們的一項重要任務就是收集、管理cbo統計數據,這些數據可以被收集、存儲,也可以在相關的實例中進行移植,以保證執行計劃的連貫性。

●在沒有使用 export_system_stats 存儲過程導出原來的統計數據以前,重新對系統的統計數據進行分析是十分危險的,因為成千上萬的sql語句的執行計劃將可能全部改變,而你卻不能恢復原來的sql性能。只有在系統的數據發生巨大變化時,才可能需要對整個系統的統計數據進行重新分析。


本小節是關于cbo的一些技術討論,原文來自 donald k. burleson 在otn上的一篇文章,具體url路徑是:
http://otn.oracle.com/oramag/webcolumns/2003/techarticles/burleson_cbo_pt1.html
翻譯中作過一些內容和段落的調整,由于水平有限,請大家參照原文閱讀,并請指出翻譯中的錯誤。

  

 

  • 本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。
  • 發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    主站蜘蛛池模板: 玉溪市| 巴彦淖尔市| 成都市| 元氏县| 马关县| 丹东市| 那坡县| 蒙山县| 玛多县| 太湖县| 林周县| 滦南县| 女性| 鄂托克前旗| 阿图什市| 孝昌县| 崇信县| 行唐县| 青浦区| 秦安县| 梁河县| 德令哈市| 望城县| 兴化市| 台南县| 宜宾县| 龙岩市| 新巴尔虎左旗| 水富县| 灌阳县| 宁夏| 永丰县| 卓资县| 泰安市| 蕲春县| 讷河市| 韩城市| 西平县| 象山县| 镇巴县| 左权县|