Oracle Tuning

      關於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 write: 直接路徑寫
  該等待發生在,等待確認所有未完成的異步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;
  假如最好的執行

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