概述
關于記憶體的配置,是最影響 Oracle性能的配置。記憶體還直接影響到其他兩個重要資源的消耗: CPU 和 IO.
那Oracle 記憶體存儲的主要内容是什麼呢?
- 程式代碼( PLSQL、 Java);
- 關于已經連接配接的會話的資訊,包括目前所有活動和非活動會話;
- 程式運作時必須的相關資訊,例如查詢計劃;
- Oracle 程序之間共享的資訊和互相交流的資訊,例如鎖;
- 那些被永久存儲在外圍存儲媒體上,被 cache 在記憶體中的資料( 如 redo log 條目,資料塊)。
每個 Oracle 資料庫都是由 Oracle Instance(執行個體)與資料庫(資料檔案,控制檔案、重做日志檔案)組成,其中所謂執行個體就是使用者同資料庫互動的媒介,使用者通過于一個執行個體相連來操作資料庫。
而執行個體又是由統一的記憶體結構( SGA,PGA, UGA)和一批記憶體駐留程序組成。
執行個體在作業系統中用 ORACLE_SID 來辨別,在 Oracle 中用參數 INSTANCE_NAME 來辨別, 它們兩個的值是相同的。
資料庫啟動時,系統首先在伺服器記憶體中配置設定系統全局區( SGA), 構成了 Oracle的記憶體結構,然後啟動若幹個常駐記憶體的作業系統程序,即組成了 Oracle 的 程序結構,記憶體區域和背景程序合稱為一個 Oracle 執行個體。
SGA (System Gloable Area)
架構圖
SGA概述
SGA 是一組為系統配置設定的共享的記憶體結構,可以包含一個資料庫執行個體的資料或控制資訊。
如果多個使用者連接配接到同一個資料庫執行個體,在執行個體的 SGA 中,資料可以被多個使用者共享。
當資料庫執行個體啟動時, SGA 的記憶體被自動配置設定;當資料庫執行個體關閉時, SGA 記憶體被回收。
SGA 是占用記憶體最大的一個區域,同時也是影響資料庫性能的重要因素。
SGA 區是可讀寫的。所有登入到執行個體的使用者都能讀取 SGA 中的資訊,而在oracle 做執行操作時,服務程序會将修改的資訊寫入 SGA 區。
SGA 主要包括了以下的資料結構:
- 資料緩沖( Buffer Cache)
- 重做日志緩沖( Redo Log Buffer)
- 共享池( Shared Pool)
- Java 池( Java Pool)
- 大池( Large Pool)
- 流池( Streams Pool — 10g 以後才有)
- 資料字典緩存( Data Dictionary Cache)
- 其他資訊(如資料庫和執行個體的狀态資訊)
SGA 中的資料字典緩存 和其他資訊 會被執行個體的背景程序所通路,它們在執行個體啟動後就固定在 SGA 中了,而且不會改變,是以這部分又稱為固定 SGA( Fixed SGA)。這部分區域的大小一般小于 100K。
Shared Pool、 Java Pool、 Large Pool 和 Streams Pool 這幾塊記憶體區的大小是相應系統參數設定而改變的,是以有通稱為可變 SGA( Variable SGA)。
SGA資訊及含義
使用有DBA權限的使用者
SQL> show parameter sga
NAME 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,說明該參數無法用 alter system語句動态修改,需要重新開機資料庫。
是以 sga_max_size 是不可以動态調整的。但是我們可以對sga_target 進行動态的調整。
SGA_MAX_SIZE
如果發現 SGA 各個記憶體總和大于 SGA_MAX_SIZE,它會将SGA_MAX_SIZE 的值修改為 SGA 各個記憶體區總和的值。
SGA 所配置設定的是虛拟記憶體,但是,在我們配置 SGA 時,一定要使整個 SGA 區都在實體記憶體中,否則,會導緻 SGA 頻繁的頁入/頁出,會極大影響系統性能。
對于 OLTP 系統, 一般的建議是将 SGA_MAX_SIZE 設為實體記憶體的 60%,PGA 設為 20%.
下面給出一些參考值:
PRE_PAGE_SGA
這個參數的預設值為FALSE,即不将全部SGA置入實體記憶體中。當設定為TRUE時,執行個體啟動會将全部SGA置入實體記憶體中。
它可以使執行個體啟動達到它的最大性能狀态,但是,啟動時間也會更長(因為為了使所有SGA都置入實體記憶體中,oracle程序需要touch所有的SGA頁)。
SQL> alter system set pre_page_sga=true scope=spfile;
複制
LOCK_SGA
為了保證SGA都被鎖定在實體記憶體中,而不必頁入/頁出,可以通過參數LOCK_SGA來控制。
這個參數預設值為FALSE,當指定為TRUE時,可以将全部SGA都鎖定在實體記憶體中。
當然,有些系統不支援記憶體鎖定,這個參數也就無效了。
SGA_TARGET
Oracle10g中引入的一個非常重要的參數。
在10g之前,SGA的各個記憶體區的大小都需要通過各自的參數指定,并且都無法超過參數指定大小的值,盡管他們之和可能并沒有達到SGA的最大限制。此外,一旦配置設定後,各個區的記憶體隻能給本區使用,互相之間是不能共享的。拿SGA中兩個最重要的記憶體區Buffer Cache和Shared Pool來說,它們兩個對執行個體的性能影響最大,但是就有這樣的沖突存在:在記憶體資源有限的情況下,某些時候資料被cache的需求非常大,為了提高buffer hit,就需要增加Buffer Cache,但由于SGA有限,隻能從其他區“搶”過來——如縮小Shared Pool,增加Buffer Cache;而有時又有大塊的PLSQL代碼被解析駐入記憶體中,導緻Shared Pool不足,甚至出現4031錯誤,又需要擴大Shared Pool,這時可能又需要人為幹預,從Buffer Cache中将記憶體奪回來。
10g 以後有了新特性:自動共享記憶體管理(Automatic Shared Memory Management ASMM)。
而控制這一特性的,也就僅僅是這一個參數SGA_TARGE。
設定這個參數後,就不需要為每個記憶體區來指定大小了。SGA_TARGET指定了SGA可以使用的最大記憶體大小,而SGA中各個記憶體的大小由Oracle自行控制,不需要人為指定。Oracle可以随時調節各個區域的大小,使之達到系統性能最佳狀态的個最合理大小,并且控制他們之和在SGA_TARGET指定的值之内。
一旦給SGA_TARGET指定值後(預設為0,即沒有啟動ASMM),就自動啟動了ASMM特性。如果不設定SGA_TARGET,則自動共享記憶體管理功能被禁止。
設定了SGA_TARGET後,以下的SGA記憶體區就可以由ASMM來自動調整:
- 共享池(Shared Pool)
- Java池(Java Pool)
- 大池(Large Pool)
- 資料緩存區(Buffer Cache)
- 流池(Streams Pool)
對于SGA_TARGET的限制,它的大小是不能超過SGA_MAX_SIZE的大小的。
要注意的是:當指定SGA_TARGET小于SGA_MAX_SIZE,執行個體重新開機後,SGA_MAX_SIZE就自動變為和SGA_TARGET一樣的值了。
在10g中,修改SGA_MAX_SIZE的值還是需要重新開機的.
SGA_TARGET帶來一個重要的好處就是,能使SGA的使用率達到最佳,進而節省記憶體成本。因為ASMM啟動後,Oracle會自動根據需要調整各個區域的大小,大大減少了某些區域記憶體緊張,而某些區域又有記憶體空閑的沖突情況出現。這也同時大大降低了出現4031錯誤的幾率。
SGA組成
Database Buffer Cache
Buffer Cache是SGA區中專門用于存放從資料檔案中讀取的的資料塊拷貝的區域。Oracle程序如果發現需要通路的資料塊已經在buffer cache中,就直接讀寫記憶體中的相應區域,而無需讀取資料檔案,進而大大提高性能.
Buffer cache對于所有oracle程序都是共享的,即能被所有oracle程序通路。
和Shared Pool一樣,buffer cache被分為多個集合,這樣能夠大大降低多CPU系統中的争用問題。
Buffer cache的管理
Oracle對于buffer cache的管理,是通過兩個重要的連結清單實作的:寫連結清單和最近最少使用連結清單(the Least Recently Used LRU).
寫連結清單所指向的是所有髒資料塊緩存(即被程序修改過,但還沒有被回寫到資料檔案中去的資料塊,此時緩沖中的資料和資料檔案中的資料不一緻)。
LRU連結清單指向的是所有空閑的緩存、pin住的緩存以及還沒有來的及移入寫連結清單的髒緩存。空閑緩存中沒有任何有用的資料,随時可以使用。而pin住的緩存是目前正在被通路的緩存。LRU連結清單的兩端就分别叫做最近使用端(the Most Recently Used MRU)和最近最少使用端(LRU)。
Buffer cache的資料塊通路
當一個 Oracle 程序通路一個緩存時,這個程序會将這塊緩存移到 LRU 連結清單中的 MRU。而當越來越多的緩沖塊被移到 MRU 端,那些已經過時的髒緩沖(即資料改動已經被寫入資料檔案中,此時緩沖中的資料和資料檔案中的資料已經一緻)則被移到 LRU 連結清單中 LRU 端。
當一個 Oracle 使用者程序第一次通路一個資料塊時,它會先查找 buffer cache中是否存在這個資料塊的拷貝。如果發現這個資料塊已經存在于 buffer cache(即命中 cache hit),它就直接讀從記憶體中取該資料塊。如果在 buffer cache 中沒有發現該資料塊(即未命中 cache miss),它就需要先從資料檔案中讀取該資料塊到buffer cache 中,然後才通路該資料塊。
命中次數與程序讀取次數之比就是我們一個衡量資料庫性能的重要名額: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
複制
一個良好性能的系統,命中率一般保持在95%左右。
Share Pool
SGA中的共享池由庫緩存(Library Cache)、字典緩存(Dictionary Cache)、用于并行執行消息的緩沖以及控制結構組成。
Shared Pool的大小由參數SHARED_POOL_SIZE決定。10g 以後可以通過SGA_TARGET 參數來自動調整。
對于Shared Pool的記憶體管理,是通過修正過的LRU算法表來實作的。
庫緩存(Library Cache)
Library Cache中包括共享SQL區(Shared SQL Areas)、PL/SQL存儲過程以及控制結構(如鎖、庫緩存句柄)。
任何使用者都可以通路共享SQL區(可以通過v$sqlarea通路)。是以庫緩存存在于SGA的共享池中。
共享SQL區和私有SQL區
Oracle會為每一條SQL語句運作(每運作一條語句Oracle都會打開一個遊标)提供一個共享SQL區(Shared SQL Areas)和私有SQL區(Private SQL Areas屬于PGA)。當發現兩個(或多個)使用者都在運作同一SQL語句時,Oracle會重新組織SQL區,使這些使用者能重用共享SQL區。但他們還會在私有SQL區中儲存一份這條SQL語句的拷貝。
一個共享SQL區中儲存了一條語句的解析樹和查詢計劃
從解析語句到配置設定共享SQL區是一個比較消耗CPU的工程。這就是為什麼我們提倡使用綁定變量的原因了。在沒有使用綁定變量時,語句中的變量的數值不同,oracle就視為一條新的語句(9i後可以通過cursor_sharing來控制),重複上面的解析、記憶體配置設定的動作,将大大消耗系統資源,降低系統性能。
PL/SQL程式單元
Oracle對于PL/SQL程式單元(存儲過程、函數、包、匿名PL/SQL塊和觸發器)的處理過程與SQL的處理方式類似。它會配置設定一個共享區來存儲被解析、編譯過的程式單元。
字典緩存(Dictionary Cache)
資料字典是有關于資料庫的參考資訊、資料庫的結構資訊和資料庫中的使用者資訊的一組表和視圖的集合,如我們常用到的V$視圖、DBA_視圖都屬于資料字典。
共享池的記憶體管理
當一條SQL語句被送出給Oracle執行,Oracle會自動執行以下的記憶體配置設定步驟:
1.Oracle檢查共享池,看是否已經存在關于這條語句的共享SQL區。如果存在,這個共享SQL區就被用于執行這條語句。而如果不存在,Oracle就從共享池中配置設定一塊新的共享SQL區給這條語句。同時,無論共享SQL區存在與否,Oracle都會為使用者配置設定一塊私有SQL區以儲存這條語句相關資訊(如變量值)。
2. Oracle為會話配置設定一個私有SQL區。私有SQL區的所在與會話的連接配接方式相關。
在以下情況下,Oracle也會将共享SQL區從共享池中釋放出來:
- 當使用ANALYZE語句更新或删除表、簇或索引的統計資訊時,所有與被分析對象相關的共享SQL區都被從共享池中釋放掉。當下一次被釋放掉的語句被執行時,又重新在一個新的共享SQL區中根據被更新過的統計資訊重新解析。
- 當對象結構被修改過後,與該對象相關的所有共SQL區都被辨別為無效(invalid)。在下一次運作語句時再重新解析語句。
- 如果資料庫的全局資料庫名(Global Database Name)被修改了,共享池中的所有資訊都會被清空掉。
- DBA通過手工方式清空共享池:ALTER SYSTEM FLUSH SHARED_POOL;
保留共享池
通過視圖
V$SHARED_POOL_RESERVED
可以查到保留池的統計資訊。其中字段REQUEST_MISSES記錄了沒有立即從空閑清單中得到可用的大記憶體段請求次數。這個值要為0。
因為保留區必須要有足夠個空閑記憶體來适應那些短期的記憶體請求,而無需将那些需要長期cache住的沒被pin住的可重建的段清除。否則就需要考慮增大SHARED_POOL_RESERVED_SIZE了。
Shared Pool的重要參數
$sgastat
複制
SHARED_POOL_SIZE
SHARED_POOL_RESERVED_SIZE:指定了共享池中緩存大記憶體對象的保留區的大小
_SHARED_POOL_RESERVED_MIN_ALLOC:設定了進入保留區的對象大小的閥值。
Redo Log Buffer重做日志緩存
Redo Log Buffer是SGA中一段儲存資料庫修改資訊的緩存。
.重做條目中包含了由于INSERT、UPDATE、DELETE、CREATE、ALTER或DROP所做的修改操作而需要對資料庫重新組織或重做的必須資訊。在必要時,重做條目還可以用于資料庫恢複。
參數LOG_BUFFER決定了Redo Log Buffer的大小。它的預設值是512K(一般這個大小都是足夠的),最大可以到4G。10g中可通過參數自動設定。當系統中存在很多的大事務或者事務數量非常多時,可能會導緻日志檔案IO增加,降低性能。這時就可以考慮增加LOG_BUFFER。
但是,Redo Log Buffer的實際大小并不是LOB_BUFFER的設定大小。為了保護Redo Log Buffer,oracle為它增加了保護頁(一般為11K)
SQL> show parameter log_buffer
NAME TYPE VALUE
------------------------------------ ----------- ------------
log_buffer integer 18317312
SQL> select * from v$sgastat where name = 'log_buffer';
POOL NAME BYTES
------------ -------------------------- ----------
log_buffer 18993152
複制
大池(large pool)
大池是屬于SGA的可變區(Variable Area)的,它不屬于共享池。
大池中隻有兩種記憶體段:空閑(free)和可空閑(freeable)記憶體段
large pool是沒有LRU連結清單的。
Java池(Java Pool)
Java池也是SGA中的一塊可選記憶體區,它也屬于SGA中的可變區。
Java池的記憶體是用于存儲所有會話中特定Java代碼和JVM中資料。Java池的使用方式依賴與Oracle服務的運作模式。
Java池的大小由參數JAVA_POOL_SIZE設定。Java Pool最大可到1G。
在Oracle 10g以後,提供了一個新的建議器——Java池建議器——來輔助DBA調整Java池大小。建議器的統計資料可以通過視圖V$JAVA_POOL_ADVICE來查詢
流池(Streams Pool)
流池是Oracle 10g中新增加的。是為了增加對流的支援。
流池也是可選記憶體區,屬于SGA中的可變區。它的大小可以通過參數STREAMS_POOL_SIZE來指定。
如果沒有被指定,oracle會在第一次使用流時自動建立。如果設定了SGA_TARGET參數,Oracle會從SGA中配置設定記憶體給流池;
如果沒有指定SGA_TARGET,則從buffer cache中轉換一部分記憶體過來給流池。轉換的大小是共享池大小的10%。
Oracle同樣為流池提供了一個建議器——流池建議器。建議器的統計資料可以通過視圖V$STREAMS_POOL_ADVICE查詢。
PGA(Program Global Area)
PGA由兩組區域組成:固定PGA和可變PGA
它的記憶體段可以通過視圖XKSMPP(另外一個視圖XKSMSP可以查到可變SGA的記憶體段資訊,他們的結構相同)查到。
PGA堆包含用于存放
X$
表的的記憶體(依賴與參數設定,包括DB_FILES、CONTROL_FILES)。
總的來說,PGA的可變區中主要分為以下三部分内容:
- 1)私有SQL區;
- 2)遊标和SQL區
- 3)會話記憶體
UGA ( The User Global Area)
UGA(User Global Area使用者全局區)由使用者會話資料、遊标狀态和索引區組成。
PGA是服務于程序的,它包含的是程序的資訊;而UGA是服務于會話的,它包含的是會話的資訊
CGA ( The Call Global Area)
與其他的全局區不同,CGA(Call Global Area調用全局區)的存在是瞬間的。它隻存在于一個調用過程中。對于執行個體的一些低層次的調用需要CGA,包括:
1)解析一條SQL語句;
2)執行一條SQL語句;
3)取一條SELECT語句的輸出值。
Java調用記憶體也配置設定在CGA中。它被分為三部分空間:堆空間、新空間和老空間。
軟體代碼區(Software Code Area)
軟體代碼區是一部分用于存放那些正在運作和可以被運作的代碼(Oracle自身的代碼)的記憶體區。Oracle代碼一般存儲在一個不同于使用者程式存儲區的軟體代碼區,而使用者程式存儲區是排他的、受保護的區域。