Oracle-内存管理解读
概述
關于內(nèi)存的配置,是最影響 Oracle性能的配置。內(nèi)存還直接影響到其他兩個重要資源的消耗: CPU 和 IO.
那Oracle 內(nèi)存存儲的主要內(nèi)容是什么呢?
- 程序代碼( PLSQL、 Java);
- 關于已經(jīng)連接的會話的信息,包括當前所有活動和非活動會話;
- 程序運行時必須的相關信息,例如查詢計劃;
- Oracle 進程之間共享的信息和相互交流的信息,例如鎖;
- 那些被永久存儲在外圍存儲介質上,被 cache 在內(nèi)存中的數(shù)據(jù)( 如 redo log 條目,數(shù)據(jù)塊)。
每個 Oracle 數(shù)據(jù)庫都是由 Oracle Instance(實例)與數(shù)據(jù)庫(數(shù)據(jù)文件,控制文件、重做日志文件)組成,其中所謂實例就是用戶同數(shù)據(jù)庫交互的媒介,用戶通過于一個實例相連來操作數(shù)據(jù)庫。
而實例又是由統(tǒng)一的內(nèi)存結構( SGA,PGA, UGA)和一批內(nèi)存駐留進程組成。
實例在操作系統(tǒng)中用 ORACLE_SID 來標識,在 Oracle 中用參數(shù) INSTANCE_NAME 來標識, 它們兩個的值是相同的。
數(shù)據(jù)庫啟動時,系統(tǒng)首先在服務器內(nèi)存中分配系統(tǒng)全局區(qū)( SGA), 構成了 Oracle的內(nèi)存結構,然后啟動若干個常駐內(nèi)存的操作系統(tǒng)進程,即組成了 Oracle 的 進程結構,內(nèi)存區(qū)域和后臺進程合稱為一個 Oracle 實例。
SGA (System Gloable Area)
架構圖
SGA概述
SGA 是一組為系統(tǒng)分配的共享的內(nèi)存結構,可以包含一個數(shù)據(jù)庫實例的數(shù)據(jù)或控制信息。
如果多個用戶連接到同一個數(shù)據(jù)庫實例,在實例的 SGA 中,數(shù)據(jù)可以被多個用戶共享。
當數(shù)據(jù)庫實例啟動時, SGA 的內(nèi)存被自動分配;當數(shù)據(jù)庫實例關閉時, SGA 內(nèi)存被回收。
SGA 是占用內(nèi)存最大的一個區(qū)域,同時也是影響數(shù)據(jù)庫性能的重要因素。
SGA 區(qū)是可讀寫的。所有登錄到實例的用戶都能讀取 SGA 中的信息,而在oracle 做執(zhí)行操作時,服務進程會將修改的信息寫入 SGA 區(qū)。
SGA 主要包括了以下的數(shù)據(jù)結構:
- 數(shù)據(jù)緩沖( Buffer Cache)
- 重做日志緩沖( Redo Log Buffer)
- 共享池( Shared Pool)
- Java 池( Java Pool)
- 大池( Large Pool)
- 流池( Streams Pool — 10g 以后才有)
- 數(shù)據(jù)字典緩存( Data Dictionary Cache)
- 其他信息(如數(shù)據(jù)庫和實例的狀態(tài)信息)
SGA 中的數(shù)據(jù)字典緩存 和其他信息 會被實例的后臺進程所訪問,它們在實例啟動后就固定在 SGA 中了,而且不會改變,所以這部分又稱為固定 SGA( Fixed SGA)。這部分區(qū)域的大小一般小于 100K。
Shared Pool、 Java Pool、 Large Pool 和 Streams Pool 這幾塊內(nèi)存區(qū)的大小是相應系統(tǒng)參數(shù)設置而改變的,所以有通稱為可變 SGA( Variable SGA)。
SGA信息及含義
使用有DBA權限的用戶
SQL> show parameter sgaNAME TYPE VALUE ------------------- ----------- -------------------------- lock_sga boolean FALSE pre_page_sga boolean FALSE sga_max_size big integer 6256M sga_target big integer 0或者查詢v$parameter
select a.name ,a.VALUE ,a.ISMODIFIED ,a.DESCRIPTION from v$parameter a where a.NAME like '%sga%';如果 ISSYS_MODIFIABLE 返回的是 false,說明該參數(shù)無法用 alter system語句動態(tài)修改,需要重啟數(shù)據(jù)庫。
所以 sga_max_size 是不可以動態(tài)調(diào)整的。但是我們可以對sga_target 進行動態(tài)的調(diào)整。
SGA_MAX_SIZE
如果發(fā)現(xiàn) SGA 各個內(nèi)存總和大于 SGA_MAX_SIZE,它會將SGA_MAX_SIZE 的值修改為 SGA 各個內(nèi)存區(qū)總和的值。
SGA 所分配的是虛擬內(nèi)存,但是,在我們配置 SGA 時,一定要使整個 SGA 區(qū)都在物理內(nèi)存中,否則,會導致 SGA 頻繁的頁入/頁出,會極大影響系統(tǒng)性能。
對于 OLTP 系統(tǒng), 一般的建議是將 SGA_MAX_SIZE 設為物理內(nèi)存的 60%,PGA 設為 20%.
下面給出一些參考值:
PRE_PAGE_SGA
這個參數(shù)的默認值為FALSE,即不將全部SGA置入物理內(nèi)存中。當設置為TRUE時,實例啟動會將全部SGA置入物理內(nèi)存中。
它可以使實例啟動達到它的最大性能狀態(tài),但是,啟動時間也會更長(因為為了使所有SGA都置入物理內(nèi)存中,oracle進程需要touch所有的SGA頁)。
SQL> alter system set pre_page_sga=true scope=spfile;LOCK_SGA
為了保證SGA都被鎖定在物理內(nèi)存中,而不必頁入/頁出,可以通過參數(shù)LOCK_SGA來控制。
這個參數(shù)默認值為FALSE,當指定為TRUE時,可以將全部SGA都鎖定在物理內(nèi)存中。
當然,有些系統(tǒng)不支持內(nèi)存鎖定,這個參數(shù)也就無效了。
SGA_TARGET
Oracle10g中引入的一個非常重要的參數(shù)。
在10g之前,SGA的各個內(nèi)存區(qū)的大小都需要通過各自的參數(shù)指定,并且都無法超過參數(shù)指定大小的值,盡管他們之和可能并沒有達到SGA的最大限制。此外,一旦分配后,各個區(qū)的內(nèi)存只能給本區(qū)使用,相互之間是不能共享的。拿SGA中兩個最重要的內(nèi)存區(qū)Buffer Cache和Shared Pool來說,它們兩個對實例的性能影響最大,但是就有這樣的矛盾存在:在內(nèi)存資源有限的情況下,某些時候數(shù)據(jù)被cache的需求非常大,為了提高buffer hit,就需要增加Buffer Cache,但由于SGA有限,只能從其他區(qū)“搶”過來——如縮小Shared Pool,增加Buffer Cache;而有時又有大塊的PLSQL代碼被解析駐入內(nèi)存中,導致Shared Pool不足,甚至出現(xiàn)4031錯誤,又需要擴大Shared Pool,這時可能又需要人為干預,從Buffer Cache中將內(nèi)存奪回來。
10g 以后有了新特性:自動共享內(nèi)存管理(Automatic Shared Memory Management ASMM)。
而控制這一特性的,也就僅僅是這一個參數(shù)SGA_TARGE。
設置這個參數(shù)后,就不需要為每個內(nèi)存區(qū)來指定大小了。SGA_TARGET指定了SGA可以使用的最大內(nèi)存大小,而SGA中各個內(nèi)存的大小由Oracle自行控制,不需要人為指定。Oracle可以隨時調(diào)節(jié)各個區(qū)域的大小,使之達到系統(tǒng)性能最佳狀態(tài)的個最合理大小,并且控制他們之和在SGA_TARGET指定的值之內(nèi)。
一旦給SGA_TARGET指定值后(默認為0,即沒有啟動ASMM),就自動啟動了ASMM特性。如果不設置SGA_TARGET,則自動共享內(nèi)存管理功能被禁止。
設置了SGA_TARGET后,以下的SGA內(nèi)存區(qū)就可以由ASMM來自動調(diào)整:
- 共享池(Shared Pool)
- Java池(Java Pool)
- 大池(Large Pool)
- 數(shù)據(jù)緩存區(qū)(Buffer Cache)
- 流池(Streams Pool)
對于SGA_TARGET的限制,它的大小是不能超過SGA_MAX_SIZE的大小的。
要注意的是:當指定SGA_TARGET小于SGA_MAX_SIZE,實例重啟后,SGA_MAX_SIZE就自動變?yōu)楹蚐GA_TARGET一樣的值了。
在10g中,修改SGA_MAX_SIZE的值還是需要重啟的.
SGA_TARGET帶來一個重要的好處就是,能使SGA的利用率達到最佳,從而節(jié)省內(nèi)存成本。因為ASMM啟動后,Oracle會自動根據(jù)需要調(diào)整各個區(qū)域的大小,大大減少了某些區(qū)域內(nèi)存緊張,而某些區(qū)域又有內(nèi)存空閑的矛盾情況出現(xiàn)。這也同時大大降低了出現(xiàn)4031錯誤的幾率。
SGA組成
Database Buffer Cache
Buffer Cache是SGA區(qū)中專門用于存放從數(shù)據(jù)文件中讀取的的數(shù)據(jù)塊拷貝的區(qū)域。Oracle進程如果發(fā)現(xiàn)需要訪問的數(shù)據(jù)塊已經(jīng)在buffer cache中,就直接讀寫內(nèi)存中的相應區(qū)域,而無需讀取數(shù)據(jù)文件,從而大大提高性能.
Buffer cache對于所有oracle進程都是共享的,即能被所有oracle進程訪問。
和Shared Pool一樣,buffer cache被分為多個集合,這樣能夠大大降低多CPU系統(tǒng)中的爭用問題。
Buffer cache的管理
Oracle對于buffer cache的管理,是通過兩個重要的鏈表實現(xiàn)的:寫鏈表和最近最少使用鏈表(the Least Recently Used LRU).
寫鏈表所指向的是所有臟數(shù)據(jù)塊緩存(即被進程修改過,但還沒有被回寫到數(shù)據(jù)文件中去的數(shù)據(jù)塊,此時緩沖中的數(shù)據(jù)和數(shù)據(jù)文件中的數(shù)據(jù)不一致)。
LRU鏈表指向的是所有空閑的緩存、pin住的緩存以及還沒有來的及移入寫鏈表的臟緩存。空閑緩存中沒有任何有用的數(shù)據(jù),隨時可以使用。而pin住的緩存是當前正在被訪問的緩存。LRU鏈表的兩端就分別叫做最近使用端(the Most Recently Used MRU)和最近最少使用端(LRU)。
Buffer cache的數(shù)據(jù)塊訪問
當一個 Oracle 進程訪問一個緩存時,這個進程會將這塊緩存移到 LRU 鏈表中的 MRU。而當越來越多的緩沖塊被移到 MRU 端,那些已經(jīng)過時的臟緩沖(即數(shù)據(jù)改動已經(jīng)被寫入數(shù)據(jù)文件中,此時緩沖中的數(shù)據(jù)和數(shù)據(jù)文件中的數(shù)據(jù)已經(jīng)一致)則被移到 LRU 鏈表中 LRU 端。
當一個 Oracle 用戶進程第一次訪問一個數(shù)據(jù)塊時,它會先查找 buffer cache中是否存在這個數(shù)據(jù)塊的拷貝。如果發(fā)現(xiàn)這個數(shù)據(jù)塊已經(jīng)存在于 buffer cache(即命中 cache hit),它就直接讀從內(nèi)存中取該數(shù)據(jù)塊。如果在 buffer cache 中沒有發(fā)現(xiàn)該數(shù)據(jù)塊(即未命中 cache miss),它就需要先從數(shù)據(jù)文件中讀取該數(shù)據(jù)塊到buffer cache 中,然后才訪問該數(shù)據(jù)塊。
命中次數(shù)與進程讀取次數(shù)之比就是我們一個衡量數(shù)據(jù)庫性能的重要指標:buffer hit ratio(buffer命中率),可以通過以下語句獲得自實例啟動至今的buffer命中率.
SQL> select (1-(sum(decode(name, 'physical reads',value,0))/(sum(decode(name, 'db block gets',value,0))2 +sum(decode(name,'consistent gets',value,0))))) * 100 "Hit Ratio" from v$sysstat;Hit Ratio ---------- 99.6854209一個良好性能的系統(tǒng),命中率一般保持在95%左右。
Share Pool
SGA中的共享池由庫緩存(Library Cache)、字典緩存(Dictionary Cache)、用于并行執(zhí)行消息的緩沖以及控制結構組成。
Shared Pool的大小由參數(shù)SHARED_POOL_SIZE決定。10g 以后可以通過SGA_TARGET 參數(shù)來自動調(diào)整。
對于Shared Pool的內(nèi)存管理,是通過修正過的LRU算法表來實現(xiàn)的。
庫緩存(Library Cache)
Library Cache中包括共享SQL區(qū)(Shared SQL Areas)、PL/SQL存儲過程以及控制結構(如鎖、庫緩存句柄)。
任何用戶都可以訪問共享SQL區(qū)(可以通過v$sqlarea訪問)。因此庫緩存存在于SGA的共享池中。
共享SQL區(qū)和私有SQL區(qū)
Oracle會為每一條SQL語句運行(每運行一條語句Oracle都會打開一個游標)提供一個共享SQL區(qū)(Shared SQL Areas)和私有SQL區(qū)(Private SQL Areas屬于PGA)。當發(fā)現(xiàn)兩個(或多個)用戶都在運行同一SQL語句時,Oracle會重新組織SQL區(qū),使這些用戶能重用共享SQL區(qū)。但他們還會在私有SQL區(qū)中保存一份這條SQL語句的拷貝。
一個共享SQL區(qū)中保存了一條語句的解析樹和查詢計劃
從解析語句到分配共享SQL區(qū)是一個比較消耗CPU的工程。這就是為什么我們提倡使用綁定變量的原因了。在沒有使用綁定變量時,語句中的變量的數(shù)值不同,oracle就視為一條新的語句(9i后可以通過cursor_sharing來控制),重復上面的解析、內(nèi)存分配的動作,將大大消耗系統(tǒng)資源,降低系統(tǒng)性能。
PL/SQL程序單元
Oracle對于PL/SQL程序單元(存儲過程、函數(shù)、包、匿名PL/SQL塊和觸發(fā)器)的處理過程與SQL的處理方式類似。它會分配一個共享區(qū)來存儲被解析、編譯過的程序單元。
字典緩存(Dictionary Cache)
數(shù)據(jù)字典是有關于數(shù)據(jù)庫的參考信息、數(shù)據(jù)庫的結構信息和數(shù)據(jù)庫中的用戶信息的一組表和視圖的集合,如我們常用到的V$視圖、DBA_視圖都屬于數(shù)據(jù)字典。
共享池的內(nèi)存管理
當一條SQL語句被提交給Oracle執(zhí)行,Oracle會自動執(zhí)行以下的內(nèi)存分配步驟:
1.Oracle檢查共享池,看是否已經(jīng)存在關于這條語句的共享SQL區(qū)。如果存在,這個共享SQL區(qū)就被用于執(zhí)行這條語句。而如果不存在,Oracle就從共享池中分配一塊新的共享SQL區(qū)給這條語句。同時,無論共享SQL區(qū)存在與否,Oracle都會為用戶分配一塊私有SQL區(qū)以保存這條語句相關信息(如變量值)。
2. Oracle為會話分配一個私有SQL區(qū)。私有SQL區(qū)的所在與會話的連接方式相關。
在以下情況下,Oracle也會將共享SQL區(qū)從共享池中釋放出來:
當使用ANALYZE語句更新或刪除表、簇或索引的統(tǒng)計信息時,所有與被分析對象相關的共享SQL區(qū)都被從共享池中釋放掉。當下一次被釋放掉的語句被執(zhí)行時,又重新在一個新的共享SQL區(qū)中根據(jù)被更新過的統(tǒng)計信息重新解析。
當對象結構被修改過后,與該對象相關的所有共SQL區(qū)都被標識為無效(invalid)。在下一次運行語句時再重新解析語句。
如果數(shù)據(jù)庫的全局數(shù)據(jù)庫名(Global Database Name)被修改了,共享池中的所有信息都會被清空掉。
DBA通過手工方式清空共享池:ALTER SYSTEM FLUSH SHARED_POOL;
保留共享池
通過視圖V$SHARED_POOL_RESERVED可以查到保留池的統(tǒng)計信息。其中字段REQUEST_MISSES記錄了沒有立即從空閑列表中得到可用的大內(nèi)存段請求次數(shù)。這個值要為0。
因為保留區(qū)必須要有足夠個空閑內(nèi)存來適應那些短期的內(nèi)存請求,而無需將那些需要長期cache住的沒被pin住的可重建的段清除。否則就需要考慮增大SHARED_POOL_RESERVED_SIZE了。
Shared Pool的重要參數(shù)
$sgastatSHARED_POOL_SIZE
SHARED_POOL_RESERVED_SIZE:指定了共享池中緩存大內(nèi)存對象的保留區(qū)的大小
_SHARED_POOL_RESERVED_MIN_ALLOC:設置了進入保留區(qū)的對象大小的閥值。
Redo Log Buffer重做日志緩存
Redo Log Buffer是SGA中一段保存數(shù)據(jù)庫修改信息的緩存。
.重做條目中包含了由于INSERT、UPDATE、DELETE、CREATE、ALTER或DROP所做的修改操作而需要對數(shù)據(jù)庫重新組織或重做的必須信息。在必要時,重做條目還可以用于數(shù)據(jù)庫恢復。
參數(shù)LOG_BUFFER決定了Redo Log Buffer的大小。它的默認值是512K(一般這個大小都是足夠的),最大可以到4G。10g中可通過參數(shù)自動設置。當系統(tǒng)中存在很多的大事務或者事務數(shù)量非常多時,可能會導致日志文件IO增加,降低性能。這時就可以考慮增加LOG_BUFFER。
但是,Redo Log Buffer的實際大小并不是LOB_BUFFER的設定大小。為了保護Redo Log Buffer,oracle為它增加了保護頁(一般為11K)
SQL> show parameter log_bufferNAME TYPE VALUE ------------------------------------ ----------- ------------ log_buffer integer 18317312SQL> select * from v$sgastat where name = 'log_buffer';POOL NAME BYTES ------------ -------------------------- ----------log_buffer 18993152大池(large pool)
大池是屬于SGA的可變區(qū)(Variable Area)的,它不屬于共享池。
大池中只有兩種內(nèi)存段:空閑(free)和可空閑(freeable)內(nèi)存段
large pool是沒有LRU鏈表的。
Java池(Java Pool)
Java池也是SGA中的一塊可選內(nèi)存區(qū),它也屬于SGA中的可變區(qū)。
Java池的內(nèi)存是用于存儲所有會話中特定Java代碼和JVM中數(shù)據(jù)。Java池的使用方式依賴與Oracle服務的運行模式。
Java池的大小由參數(shù)JAVA_POOL_SIZE設置。Java Pool最大可到1G。
在Oracle 10g以后,提供了一個新的建議器——Java池建議器——來輔助DBA調(diào)整Java池大小。建議器的統(tǒng)計數(shù)據(jù)可以通過視圖V$JAVA_POOL_ADVICE來查詢
流池(Streams Pool)
流池是Oracle 10g中新增加的。是為了增加對流的支持。
流池也是可選內(nèi)存區(qū),屬于SGA中的可變區(qū)。它的大小可以通過參數(shù)STREAMS_POOL_SIZE來指定。
如果沒有被指定,oracle會在第一次使用流時自動創(chuàng)建。如果設置了SGA_TARGET參數(shù),Oracle會從SGA中分配內(nèi)存給流池;
如果沒有指定SGA_TARGET,則從buffer cache中轉換一部分內(nèi)存過來給流池。轉換的大小是共享池大小的10%。
Oracle同樣為流池提供了一個建議器——流池建議器。建議器的統(tǒng)計數(shù)據(jù)可以通過視圖V$STREAMS_POOL_ADVICE查詢。
PGA(Program Global Area)
PGA由兩組區(qū)域組成:固定PGA和可變PGA
它的內(nèi)存段可以通過視圖X$KSMPP(另外一個視圖X$KSMSP可以查到可變SGA的內(nèi)存段信息,他們的結構相同)查到。
PGA堆包含用于存放X$表的的內(nèi)存(依賴與參數(shù)設置,包括DB_FILES、CONTROL_FILES)。
總的來說,PGA的可變區(qū)中主要分為以下三部分內(nèi)容:
- 1)私有SQL區(qū);
- 2)游標和SQL區(qū)
- 3)會話內(nèi)存
UGA ( The User Global Area)
UGA(User Global Area用戶全局區(qū))由用戶會話數(shù)據(jù)、游標狀態(tài)和索引區(qū)組成。
PGA是服務于進程的,它包含的是進程的信息;而UGA是服務于會話的,它包含的是會話的信息
CGA ( The Call Global Area)
與其他的全局區(qū)不同,CGA(Call Global Area調(diào)用全局區(qū))的存在是瞬間的。它只存在于一個調(diào)用過程中。對于實例的一些低層次的調(diào)用需要CGA,包括:
1)解析一條SQL語句;
2)執(zhí)行一條SQL語句;
3)取一條SELECT語句的輸出值。
Java調(diào)用內(nèi)存也分配在CGA中。它被分為三部分空間:堆空間、新空間和老空間。
軟件代碼區(qū)(Software Code Area)
軟件代碼區(qū)是一部分用于存放那些正在運行和可以被運行的代碼(Oracle自身的代碼)的內(nèi)存區(qū)。Oracle代碼一般存儲在一個不同于用戶程序存儲區(qū)的軟件代碼區(qū),而用戶程序存儲區(qū)是排他的、受保護的區(qū)域。
總結
以上是生活随笔為你收集整理的Oracle-内存管理解读的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle-等待事件解读
- 下一篇: Oracle-SYSAUX表空间解读