Oracle的內存配置與oracle性能息息相關(guān)。而且關(guān)于內存的錯誤(如4030、4031錯誤)都是十分令人頭疼的問(wèn)題??梢哉f(shuō),關(guān)于內存的配置,是最影響Oracle性能的配置。內存還直接影響到其他兩個(gè)重要資源的消耗:CPU和IO。
首先,看看Oracle內存存儲的主要內容是什么:
程序代碼(PLSQL、Java);
關(guān)于已經(jīng)連接的會(huì )話(huà)的信息,包括當前所有活動(dòng)和非活動(dòng)會(huì )話(huà);
程序運行時(shí)必須的相關(guān)信息,例如查詢(xún)計劃;
Oracle進(jìn)程之間共享的信息和相互交流的信息,例如鎖;
那些被永久存儲在外圍存儲介質(zhì)上,被cache在內存中的數據(如redo log條目,數據塊)。
此外,需要記住的一點(diǎn)是,Oracle的內存是與實(shí)例對應的。也就是說(shuō),一個(gè)實(shí)例就有一個(gè)獨立的內存結構。
先從Oracle內存的組成架構介紹。
1. Oracle的內存架構組成
Oracle的內存,從總體上講,可以分為兩大塊:共享部分(主要是SGA)和進(jìn)程獨享部分(主要是PGA和UGA)。而這兩部分內存里面,根據功能不同,還分為不同內存池(Pool)和內存區(Area)。下面就是Oracle內存構成框架圖:
SGA
Share Pool
Buffer Cache
Redo Log Buffer
Java Pool
Stream Pool(10g)
Large Pool
PGA*n
Bitmap merge area
Sort Area
Hash Area
UGA*n
CUA*n
下面分別介紹這兩塊內存區。
1.1. SGA(System Global Area)
SGA(System Global Area 系統全局區域)是一組包含一個(gè)Oracle實(shí)例的數據和控制信息的共享內存結構。這句話(huà)可以說(shuō)是SGA的定義。雖然簡(jiǎn)單,但其中闡述了SGA幾個(gè)很重要的特性:1、SGA的構成——數據和控制信息,我們下面會(huì )詳細介紹;2、SGA是共享的,即當有多個(gè)用戶(hù)同時(shí)登錄了這個(gè)實(shí)例,SGA中的信息可以被它們同時(shí)訪(fǎng)問(wèn)(當涉及到互斥的問(wèn)題時(shí),由latch和enquence控制);3、一個(gè)SGA只服務(wù)于一個(gè)實(shí)例,也就是說(shuō),當一臺機器上有多個(gè)實(shí)例運行時(shí),每個(gè)實(shí)例都有一個(gè)自己的SGA,盡管SGA來(lái)自于OS的共享內存區,但實(shí)例之間不能相互訪(fǎng)問(wèn)對方的SGA區。
Oracle進(jìn)程和一個(gè)SGA就構成了一個(gè)Oracle實(shí)例。當實(shí)例啟動(dòng)時(shí),Oracle會(huì )自動(dòng)從系統中分配內存給SGA,而實(shí)例關(guān)閉時(shí),操作系統會(huì )回收這些內存。下面就是當實(shí)例啟動(dòng)后,顯示已經(jīng)分配了SGA:
SQL> startup ORACLE instance started. Total System Global Area 289406976 bytes Fixed Size 1248576 bytes Variable Size 117441216 bytes Database Buffers 163577856 bytes Redo Buffers 7139328 bytes Database mounted. Database opened. SQL>
SGA區是可讀寫(xiě)的。所有登錄到實(shí)例的用戶(hù)都能讀取SGA中的信息,而在oracle做執行操作時(shí),服務(wù)進(jìn)程會(huì )將修改的信息寫(xiě)入SGA區。
SGA主要包括了以下的數據結構:
數據緩沖(Buffer Cache)
重做日志緩沖(Redo Log Buffer)
共享池(Shared Pool)
Java池(Java Pool)
大池(Large Pool)
流池(Streams Pool --- 10g以后才有)
數據字典緩存(Data Dictionary Cache)
其他信息(如數據庫和實(shí)例的狀態(tài)信息)
最后的兩種內存信息會(huì )被實(shí)例的后臺進(jìn)程所訪(fǎng)問(wèn),它們在實(shí)例啟動(dòng)后就固定在SGA中了,而且不會(huì )改變,所以這部分又稱(chēng)為固定SGA(Fixed SGA)。這部分區域的大小一般小于100K。
此外,用于并非進(jìn)程控制的鎖(latch)的信息也包含在SGA區中。
Shared Pool、Java Pool、Large Pool和Streams Pool這幾塊內存區的大小是相應系統參數設置而改變的,所以有通稱(chēng)為可變SGA(Variable SGA)。
1.1.1. SGA的重要參數和特性
在設置SGA時(shí),有一些很重要的參數,它們設置正確與否,會(huì )直接影響到系統的整體性能。下面一一介紹他們:
· SGA_MAX_SIZE
SGA區包括了各種緩沖區和內存池,而大部分都可以通過(guò)特定的參數來(lái)指定他們的大小。但是,作為一個(gè)昂貴的資源,一個(gè)系統的物理內存大小是有限。盡管對于CPU的內存尋址來(lái)說(shuō),是無(wú)需關(guān)系實(shí)際的物理內存大小的(關(guān)于這一點(diǎn),后面會(huì )做詳細的介紹),但是過(guò)多的使用虛擬內存導致page in/out,會(huì )大大影響系統的性能,甚至可能會(huì )導致系統crash。所以需要有一個(gè)參數來(lái)控制SGA使用虛擬內存的最大大小,這個(gè)參數就是SGA_MAX_SIZE。
當實(shí)例啟動(dòng)后,各個(gè)內存區只分配實(shí)例所需要的最小大小,在隨后的運行過(guò)程中,再根據需要擴展他們的大小,而他們的總和大小受到了SGA_MAX_SIZE的限制。
當試圖增加一個(gè)內存的大小,并且如果這個(gè)值導致所有內存區大小總和大于SGA_MAX_SIZE時(shí),oracle會(huì )提示錯誤,不允許修改。
當然,如果在設置參數時(shí),指定區域為spfile時(shí)(包括修改SGA_MAX_SIZE本身),是不會(huì )受到這個(gè)限制的。這樣就可能出現這樣的情況,在spfile中,SGA各個(gè)內存區設置大小總和大于SGA_MAX_SIZE。這時(shí),oracle會(huì )如下處理:當實(shí)例再次啟動(dòng)時(shí),如果發(fā)現SGA各個(gè)內存總和大于SGA_MAX_SIZE,它會(huì )將SGA_MAX_SIZE的值修改為SGA各個(gè)內存區總和的值。
SGA所分配的是虛擬內存,但是,在我們配置SGA時(shí),一定要使整個(gè)SGA區都在物理內存中,否則,會(huì )導致SGA頻繁的頁(yè)入/頁(yè)出,會(huì )極大影響系統性能。
對于OLTP系統,我個(gè)人建議可以如下配置SGA_MAX_SIZE(一般有經(jīng)驗的DBA都會(huì )有自己的默認配置大小,你也可以通過(guò)一段時(shí)間的觀(guān)察、調整自己的系統來(lái)得到適合本系統的參數配置):
系統內存
SGA_MAX_SIZE值
1G
400-500M
2G
1G
4G
2500M
8G
5G
SGA的實(shí)際大小可以通過(guò)以下公式估算:
SGA實(shí)際大小 = DB_CACHE_SIZE + DB_KEEP_CACHE_SIZE + DB_RECYCLE_CACHE_SIZE + DB_nk_CACHE_SIZE + SHARED_POOL_SIZE + LARGE_POOL_SIZE + JAVA_POOL_SIZE + STREAMS_POOL_SIZE(10g中的新內存池) + LOG_BUFFERS+11K(Redo Log Buffer的保護頁(yè)) + 1MB + 16M(SGA內部?jì)却嫦?,適合于9i及之前版本)
公式種涉及到的參數在下面的內容種會(huì )一一介紹。
· PRE_PAGE_SGA
我們前面提到,oracle實(shí)例啟動(dòng)時(shí),會(huì )只載入各個(gè)內存區最小的大小。而其他SGA內存只作為虛擬內存分配,只有當進(jìn)程touch到相應的頁(yè)時(shí),才會(huì )置換到物理內存中。但我們也許希望實(shí)例一啟動(dòng)后,所有SGA都分配到物理內存。這時(shí)就可以通過(guò)設置PRE_PAGE_SGA參數來(lái)達到目的了。
這個(gè)參數的默認值為FALSE,即不將全部SGA置入物理內存中。當設置為T(mén)RUE時(shí),實(shí)例啟動(dòng)會(huì )將全部SGA置入物理內存中。它可以使實(shí)例啟動(dòng)達到它的最大性能狀態(tài),但是,啟動(dòng)時(shí)間也會(huì )更長(cháng)(因為為了使所有SGA都置入物理內存中,oracle進(jìn)程需要touch所有的SGA頁(yè))。
我們可以通過(guò)TopShow工具(本站原創(chuàng )工具,可在
http://www.HelloDBA.com/Download/TopShow.html中下載)來(lái)觀(guān)察windows(Unix下的內存監控比較復雜,這里暫不舉例)下參數修改前后的對比。
PRE_PAGE_SGA為FALSE:
SQL> show parameter sga NAME TYPE VALUE ------------------------------------ ----------- -------------------------- lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 276M sga_target big integer 276M SQL> startup force ORACLE instance started. Total System Global Area 289406976 bytes Fixed Size 1248576 bytes Variable Size 117441216 bytes Database Buffers 163577856 bytes Redo Buffers 7139328 bytes Database mounted. Database opened. SQL> 啟動(dòng)后,Oracle的內存情況
可以看到,實(shí)例啟動(dòng)后,oracle占用的物理內存只有168M,遠小于SGA的最大值288M(實(shí)際上,這部分物理內存中還有一部分進(jìn)程的PGA和Oracle Service占用的內存),而虛擬內存則為340M。
將PRE_PAGE_SGA修改為T(mén)RUE,重啟實(shí)例:
SQL> alter system set pre_page_sga=true scope=spfile; System altered. SQL> startup force ORACLE instance started. Total System Global Area 289406976 bytes Fixed Size 1248576 bytes Variable Size 117441216 bytes Database Buffers 163577856 bytes Redo Buffers 7139328 bytes Database mounted. Database opened. 再觀(guān)察啟動(dòng)后Oracle的內存分配情況:
這時(shí)看到,實(shí)例啟動(dòng)后物理內存達到了最大343M,于虛擬內存相當。這時(shí),oracle實(shí)例已經(jīng)將所有SGA分配到物理內存。
當參數設置為T(mén)RUE時(shí),不僅在實(shí)例啟動(dòng)時(shí),需要touch所有的SGA頁(yè),并且由于每個(gè)oracle進(jìn)程都會(huì )訪(fǎng)問(wèn)SGA區,所以每當一個(gè)新進(jìn)程啟動(dòng)時(shí)(在Dedicated Server方式中,每個(gè)會(huì )話(huà)都會(huì )啟動(dòng)一個(gè)Oracle進(jìn)程),都會(huì )touch一遍該進(jìn)程需要訪(fǎng)問(wèn)的所有頁(yè)。因此,每個(gè)進(jìn)程的啟動(dòng)時(shí)間頁(yè)增長(cháng)了。所以,這個(gè)參數的設置需要根據系統的應用情況來(lái)設定。
在這種情況下,進(jìn)程啟動(dòng)時(shí)間的長(cháng)短就由系統內存的頁(yè)的大小來(lái)決定了。例如,SGA大小為100M,當頁(yè)的大小為4K時(shí),進(jìn)程啟動(dòng)時(shí)需要訪(fǎng)問(wèn)100000/4=25000個(gè)頁(yè),而如果頁(yè)大小為4M時(shí),進(jìn)程只需要訪(fǎng)問(wèn)100/4=25個(gè)頁(yè)。頁(yè)的大小是由操作系統指定的,并且是無(wú)法修改的。
但是,要記住一點(diǎn):PRE_PAGA_SGA只是在啟動(dòng)時(shí)將物理內存分配給SGA,但并不能保證系統在以后的運行過(guò)程不會(huì )將SGA中的某些頁(yè)置換到虛擬內存中,也就是說(shuō),盡管設置了這個(gè)參數,還是可能出現Page In/Out。如果需要保障SGA不被換出,就需要由另外一個(gè)參數LOCK_SGA來(lái)控制了。
· LOCK_SGA
上面提到,為了保證SGA都被鎖定在物理內存中,而不必頁(yè)入/頁(yè)出,可以通過(guò)參數LOCK_SGA來(lái)控制。這個(gè)參數默認值為FALSE,當指定為T(mén)RUE時(shí),可以將全部SGA都鎖定在物理內存中。當然,有些系統不支持內存鎖定,這個(gè)參數也就無(wú)效了。
· SGA_TARGET
這里要介紹的時(shí)Oracle10g中引入的一個(gè)非常重要的參數。在10g之前,SGA的各個(gè)內存區的大小都需要通過(guò)各自的參數指定,并且都無(wú)法超過(guò)參數指定大小的值,盡管他們之和可能并沒(méi)有達到SGA的最大限制。此外,一旦分配后,各個(gè)區的內存只能給本區使用,相互之間是不能共享的。拿SGA中兩個(gè)最重要的內存區Buffer Cache和Shared Pool來(lái)說(shuō),它們兩個(gè)對實(shí)例的性能影響最大,但是就有這樣的矛盾存在:在內存資源有限的情況下,某些時(shí)候數據被cache的需求非常大,為了提高buffer hit,就需要增加Buffer Cache,但由于SGA有限,只能從其他區“搶”過(guò)來(lái)——如縮小Shared Pool,增加Buffer Cache;而有時(shí)又有大塊的PLSQL代碼被解析駐入內存中,導致Shared Pool不足,甚至出現4031錯誤,又需要擴大Shared Pool,這時(shí)可能又需要人為干預,從Buffer Cache中將內存奪回來(lái)。
有了這個(gè)新的特性后,SGA中的這種內存矛盾就迎刃而解了。這一特性被稱(chēng)為自動(dòng)共享內存管理(Automatic Shared Memory Management ASMM)。而控制這一特性的,也就僅僅是這一個(gè)參數SGA_TARGE。設置這個(gè)參數后,你就不需要為每個(gè)內存區來(lái)指定大小了。SGA_TARGET指定了SGA可以使用的最大內存大小,而SGA中各個(gè)內存的大小由Oracle自行控制,不需要人為指定。Oracle可以隨時(shí)調節各個(gè)區域的大小,使之達到系統性能最佳狀態(tài)的個(gè)最合理大小,并且控制他們之和在SGA_TARGET指定的值之內。一旦給SGA_TARGET指定值后(默認為0,即沒(méi)有啟動(dòng)ASMM),就自動(dòng)啟動(dòng)了ASMM特性。
設置了SGA_TARGET后,以下的SGA內存區就可以由ASMM來(lái)自動(dòng)調整:
共享池(Shared Pool)
Java池(Java Pool)
大池(Large Pool)
數據緩存區(Buffer Cache)
流池(Streams Pool)
對于SGA_TARGET的限制,它的大小是不能超過(guò)SGA_MAX_SIZE的大小的。
SQL> show parameter sga NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 276M sga_target big integer 276M SQL> SQL> SQL> SQL> alter system set sga_target=280M; alter system set sga_target=280M * ERROR at line 1: ORA-02097: parameter cannot be modified because specified value is invalid ORA-00823: Specified value of sga_target greater than sga_max_size 另外,當指定SGA_TARGET小于SGA_MAX_SIZE,實(shí)例重啟后,SGA_MAX_SIZE就自動(dòng)變?yōu)楹蚐GA_TARGET一樣的值了。
SQL> show parameter sga NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 276M sga_target big integer 276M SQL> alter system set sga_target=252M; System altered. SQL> show parameter sga NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 276M sga_target big integer 252M SQL> startup force ORACLE instance started. Total System Global Area 264241152 bytes Fixed Size 1248428 bytes Variable Size 117441364 bytes Database Buffers 138412032 bytes Redo Buffers 7139328 bytes Database mounted. Database opened. SQL> show parameter sga NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 252M sga_target big integer 252M SQL> 對于SGA_TARGET,還有重要一點(diǎn)就是,它的值可以動(dòng)態(tài)修改(在SGA_MAX_SIZE范圍內)。在10g之前,如果需要修改SGA的大?。葱薷腟GA_MAX_SIZE的值)需要重啟實(shí)例才能生效。當然,在10g中,修改SGA_MAX_SIZE的值還是需要重啟的。但是有了SGA_TARGET后,可以將SGA_MAX_SIZE設置偏大,再根據實(shí)際需要調整SGA_TARGET的值(我個(gè)人不推薦頻繁修改SGA的大小,SGA_TARGET在實(shí)例啟動(dòng)時(shí)設置好,以后不要再修改)。
SGA_TARGET帶來(lái)一個(gè)重要的好處就是,能使SGA的利用率達到最佳,從而節省內存成本。因為ASMM啟動(dòng)后,Oracle會(huì )自動(dòng)根據需要調整各個(gè)區域的大小,大大減少了某些區域內存緊張,而某些區域又有內存空閑的矛盾情況出現。這也同時(shí)大大降低了出現4031錯誤的幾率。
這個(gè)參數使32位平臺使用擴展緩沖緩存基址,以支持支持4GB多物理內存。設置此參數,可以使SGA突破在32位系統中的2G最大限制。64位平臺中,這個(gè)參數被忽略。