Oracle記憶體結構(二)----Shared Pool的詳細資訊

jss001發表於2009-02-12

The Shared Pool

The Shared Pool在SGA中是SIZE較大的一個部分.有很多DBA沒搞明白Shared Pool是用來做什麼的,不知道怎麼定Shared Pool的合適的SIZE.就隨意的將它的SIZE搞得很大.有時候可能是不夠大,但更多的時候是在浪費記憶體空間.而且太大的Shared Pool會影響效能.

塊(Chunk):

要更好的理解Shared Pool,得對X$KSMSP表多做點研究.這個表中的每一個記錄行對應的是Shared Pool記憶體中的一個Chunk(塊).

SQL> select ksmchcom, ksmchcls, ksmchsiz from x$ksmsp;

KSMCHCOM KSMCHCLS KSMCHSIZ

---------------- -------- ----------

KGL handles recr 496

PL/SQL MPCODE recr 1624

dictionary cach freeabl 4256

free memory free 1088

library cache freeabl 568

library cache recr 584

multiblock rea freeabl 2072

permanent memor perm 1677104

row cache lru recr 48

session param v freeabl 2936

sql area freeabl 2104

sql area recr 1208

上面的是對這個表查詢的例子.(對整個表的查詢有5726行左右的記錄)

在 每個Shared Pool Chunk已經分配好之後,程式碼將語句轉化並使其有作用的這一過程實際上就稱為一次分配.這個語句可以在X$KSMSP表中的KSMCHCOM欄位看到, 描述分配的記憶體Chunk.每一個Chunk都要比它所包含的物件要大,因為每個Chunk都有多出來16位元組的頭資訊用於儲存確認Chunk的型別、類 別和大小SIZE還有用於Shared Pool管理的連結指標.

記憶體Chunk主要有四種類別,可以從X$KSMSP表中的KSMCHCLS看到.

free:這種類別的Chunk稱為Free Chunk.它不包含有效的物件,可以自由分配.

recr:可重建的Chunk(Recreatable Chunk),這種Chunk有包含物件,而這些物件在必要的時候是可以臨時被刪除並在有需要的情況下進行重建.一個例子,包含Shared SQL Statements的Chunks就可以重建

freeabl: 可釋放的Chunk(Freeabl Chunk),這種Chunk也有包含物件,這些物件在一個session的生存期間是經常可用的而在session斷掉之後就不可用.這些Chunks 可以在session斷開之前進行釋放,可以部分釋放也可以全部釋放.Freeable Chunk是不能臨時被刪除的,因為它是不可重建的.

perm:永久性的記憶體Chunk(Permanent memory Chunk).它包含的物件是不能被釋放的,是永久存在於記憶體中的.一些大的永久性的記憶體Chunk內部也包含一定量的free space.可以根據需要釋放給shared poo.

select

ksmchcom contents,

count(*) chunks,

sum(decode(ksmchcls, 'recr', ksmchsiz)) recreatable,

sum(decode(ksmchcls, 'freeabl', ksmchsiz)) freeable,

sum(ksmchsiz) total

from

sys.x_$ksmsp

where

inst_id = userenv('Instance') and

ksmchcls not like 'R%'

group by

ksmchcom

KSMCHCOM CHUNKS RECR FREEABL TOTAL

---------------- ---------- ---------- ---------- ----------

KGFF heap 6 1296 2528 3824

KGK contexts 2 2400 2400

KGK heap 2 1136 1136

KGL handles 571 178616 178616

KQLS heap 404 87952 524888 612840

PL/SQL DIANA 274 42168 459504 501672

PL/SQL MPCODE 57 14560 88384 102944

PLS cca hp desc 1 168 168

PLS non-lib hp 1 2104 2104

character set m 5 23504 23504

dictionary cach 108 223872 223872

fixed allocatio 9 360 360

free memory 185 614088

kzull 1 48 48

library cache 1612 268312 356312 624624

multiblock rea 1 2072 2072

permanent memor 1 1677104

reserved stoppe 2 48

row cache lru 24 1168 1168

session param v 8 23488 23488

sql area 983 231080 1303792 1534872

table columns 19 18520 18520

table definiti 2 176 176

上面這個查詢可以得到Shared Pool中所有Chunks的型別,類別和大小SIZE等相關資訊.上面只列出部分記錄.

Free Lists:

Shared Pool中的Free Chunks,於它們的大小為基準被組織成Free Lists或者Buckets.下面的一張表是Bucket號和Free Chunks SIZE的對應關係:

用下面這個指令碼可以查詢到Chunks數和每個Free List中的Free Space量.

select

decode(sign(ksmchsiz - 80), -1, 0, trunc(1/log(ksmchsiz - 15, 2)) - 5)

bucket,

sum(ksmchsiz) free_space,

count(*) free_chunks,

trunc(avg(ksmchsiz)) average_size,

max(ksmchsiz) biggest

from

sys.x_$ksmsp

where

inst_id = userenv('Instance') and

ksmchcls = 'free'

group by

decode(sign(ksmchsiz - 80), -1, 0, trunc(1/log(ksmchsiz - 15, 2)) - 5)

BUCKET FREE_SPACE FREE_CHUNKS AVERAGE_SIZE BIGGEST

---------- ---------- ----------- ------------ ----------

0 166344 3872 42 72

1 32208 374 86 96

4 928 1 928 928

6 11784 4 2946 3328

當 一個程式需要Shared Pool Memory分配一個Chunk時,它首先會到Free Lists中查詢與它所需的SIZE匹配的Chunk.如果跟所需的SIZE沒有確切相符的Chunk可以分配則會繼續在Free Lists中尋找一個更大的Chunk.如果找到的Chunk有24位元組或者更多,則這個Chunk將會被分裂開來使用,將其餘的Free Space部分返還到Free Lists中.如果上面的都找不到,則會從一個非空的Free Lists中找一個最小的Chunk給它使用.最後的方式是以LRU機制對Free Lists進行描述

Free Lists的描述,管理和Chunk的分配都是在Shared Pool Lathes的保護下進行的.如果Shared Pool包含有大量的小的Free Chunks時,在對這個特殊的Free Lists進行描述時,Shared Pool Lathes將會被佔有比較長的一段時間.實際上,經常出現的Shared Pool Lathes的競爭和等待就是因為包含了大量的小的Free Chunks.所以增加Shared Pool 的SIZE並不能減少Shared Pool Lathes Contention而且還會使得這個競爭更加嚴重,這就是前面提到的將Shared Pool的SIZE設為很大並不一定會提高效能原因.

LRU Lists:

如果一個程式沒辦法從Shared Pool Free Lists中獲得一個Free Chunk,則它會從Shared Pool中刪除一個包含有Recreatable物件的Chunks來釋放足夠大的Chunks滿足自己的使用.

Recreatable Chunks有兩個種類:一種是Pinned在記憶體中的,一種是沒有Pinned在記憶體中的.Pinned在記憶體中的Chunks跟用 DBMS_SHARED_POOL.KEEP執行來KEEP在Shared Pool中是不一樣的. DBMS_SHARED_POOL.KEEP是需要DBA來干預執行的,並且只能放在library cache中.而Pinned Chunks是自動執行的,它在Chunks包含正在使用的物件時就會自動被pinned在Shared Pool中.Pinned Recreatable Chunks是不能釋放空間的,而Unpinned Recreatable Chunks是可以釋放出來的.

在Shared Pool中,Unpinned Chunks被組織成兩個Lists,它們都是以LRU機制來排列的.分別被稱為臨時的LRU List和迴圈的LRU List. Chunks在Unpinned時放在MRU(most recently used)的最後面,在它們pinned時將會從這個MRU List中刪除.

在一個程式需要新分配一部分Shared Pool Memory記憶體時,Chunks也會從LRU List的最尾端刪除.Chunks以每8個chunks為一個集而被flushed(暫時說為清空)-----首先是從臨時的LRU List,然後再從迴圈的LRU List. Chunks是在不考慮SIZE的大小並且以LRU機制被flushed的.有一些Chunks是不能被 flushed的,如用DBMS_SHARED_POOL.KEEP執行後的包含library cache 物件的Chunks是不能被 flushed.這些Chunks透過pinned方式來代替被刪除.

Unpinned Recreatable Chunks兩種型別的LRU Lists: 臨時的LRU List和迴圈的LRU List的長度可以從fixed表X$KGHLU查詢到,還有已經flush掉的Chunks數,由於pinned和unpinned而加入到LRU List或者是從LRU List刪除的Chunks數.從X$KGHLU表也可以知道LRU Lists被flushed完全但不成功(不理解)的次數和最近一次請求Chunk失敗的所需要Chunk SIZE.具體看下面的語句:

column kghlurcr heading "RECURRENT|CHUNKS"

column kghlutrn heading "TRANSIENT|CHUNKS"

column kghlufsh heading "FLUSHED|CHUNKS"

column kghluops heading "PINS AND|RELEASES"

column kghlunfu heading "ORA-4031|ERRORS"

column kghlunfs heading "LAST ERROR|SIZE"

select

kghlurcr,

kghlutrn,

kghlufsh,

kghluops,

kghlunfu,

kghlunfs

from

sys.x_$kghlu

where

inst_id = userenv('Instance')

/

RECURRENT TRANSIENT FLUSHED PINS AND ORA-4031 LAST ERROR

CHUNKS CHUNKS CHUNKS RELEASES ERRORS SIZE

---------- ---------- ---------- ---------- ---------- -----------

121 164 148447 4126701 0 0

LRU Lists的長度和flush率跟前臺應用和工作流量的變化有很大的依賴關係.長或短的LRU Lists都不會造成問題,但是Chunks flush則在對記憶體的健康管理中佔用很重要的一部分.如果TRANSIENT CHUNKS長於RECURRENT CHUNKS則說明Shared Pool SIZE太大了.而Chunks flush到其它的LRU操作的命中率如果大於1/20則說明Shared Pool SIZE太小.(上面這個是別人的經驗介紹)

Spare free memory:

如果一個大的記憶體請求從Free Lists和LRU Lists Flushing都不能分配,Oracle則會用另外的一種方式來實現.

Oracle 的重排序並不是用來接合空閒記憶體的.當一些Chunks已經被釋放它們將會跟後面的Chunk接合一起使用(這裡所謂的接合是前面一個free chunk跟後面一個free chunk接合在一起成為一個更大的free chunk).一般地,Oracle只會在顯示的執行命令ALTER SYSTEM FLUSH SHARED POOL後才會以完全的方式來接合Shared Pool中的free space.即使當Shared Pool有足夠的連續的記憶體段時,記憶體請求分配也有可能失敗的.如果空閒記憶體被分成多個小的Chunks時,也有可能沒法滿足大的記憶體請求分配.

為 了滿足較大的記憶體請求分配,Oracle用重排序的方式來釋放更多的記憶體給Shared Pool. 實際上,Oracle在例項啟動的時候只分配大概一半的原Shared Pool SIZE給Shared Pool(即劃分shared_pool_size的一半記憶體出來給Shared Pool.等以後需要用到更多時再用重排序的方式秋釋放給它).Oracle用這種方式來確保Shared Pool不會產生太多的碎片.

Oracle 的多餘空閒記憶體(Spare free memory),在Shared Pool中被隱藏在永久性的記憶體Chunks(permanent memory chunks)中.這些記憶體不在Shared Pool的Free Lists中,所以是不能立即被分配出來使用的.在V$SGASTAT可以看到free memory statistics.在有必要的時候Spare Free Memory Chunks才會被釋放給Shared Pool.在這些Spare Free Memory已經被分配完給Shared Pool之後,還有對Shared Pool Memory請求但是分配不到Free Memory,則會產生ORA-4031’unable to allocate x bytes of shared memory’錯誤.如果在資料庫執行於高峰登入量一段時間之後,Oracle還有剩餘較大部分的Spare Free Memory則說明此時所設定的shared_pool_size過大.可以透過下面的指令碼檢視剩餘的Spare Free Memory.

select

avg(v.value) shared_pool_size,

greatest(avg(s.ksmsslen) - sum(p.ksmchsiz), 0) spare_free,

to_char(

100 * greatest(avg(s.ksmsslen) - sum(p.ksmchsiz), 0) / avg(v.value),

'99999'

) || '%' wastage

from

sys.x_$ksmss s,

sys.x_$ksmsp p,

sys.v_$parameter v

where

s.inst_id = userenv('Instance') and

p.inst_id = userenv('Instance') and

p.ksmchcom = 'free memory' and

s.ksmssnam = 'free memory' and

v.name = 'shared_pool_size'

/

The Reserved List:

一般,最大的Chunks也不會超過5000bytes的.如果有請求更大的Chunks的話,Oracle用的是另外一種方式,即下面說的 Reserved Shared Pool,而不會到Shared Pool Free Lists和LRU Lists中尋找適應的或者更大SIZE的Chunks來給它使用.

Oracle為大的 Chunks保留了Shared Pool的一部分.預設保留的是shared_pool_size的5%.也可以透過引數shared_pool_reserved_size設定其大 小.對應引數名,這一部分是從Shared Pool中取出的一部分SIZE.

超過 5000bytes的Chunks會被放到Shared Pool的保留部分中,開始是可以透過隱含引數_SHARED_POOL_RESERVED_MIN_ALLOC來設定的,但是在例項啟動之後是不能修改 的.所以小的Chunks是不會被放到Shared Pool的保留部分中來的. Shared Pool的保留部分中的Free Memory不被包含在一般的Shared Pool Free Lists中,而是放在一個單獨的Reserved Free List(針對Reserved Shared Pool)中.然而, Reserved Shared Pool是沒有屬於它自己的LRU Lists 來為Unpinned Recreatable Chunks服務的.因此,在為一般的Free Lists釋放記憶體空間時大的Chunks是不會被flushed(清空)的.而在為Reserved Shared Pool Free Lists釋放記憶體空間時,小的Chunks是不會被flushed(Reserved Shared Pool Free Lists只有大的Chunks).(這裡的大的Chunks我們指的是超過5000bytes的Chunks)

在 V$SHARED_POOL_RESERVED檢視我們可以檢視Reserved Shared Pool的統計資訊.特別是欄位REQUEST_MISSES,它顯示的是從Reserved Shared Pool Free Lists中請求大的Chunks沒有即刻滿足的次數.這個值應當為0.也就是說,在沒有flush Unpinned Recreatable Chunks的情況下在Reserved Shared Pool應該有足夠多的Free Memory來滿足短時間的Freeable memory的請求.檢視V$SHARED_POOL_RESERVED檢視中的USED_SPACE欄位來確定多大的Reserved Shared Pool SIZE才是適當的.用下面的指令碼檢視Reserved Shared Pool 的SIZE和HWM以及使用率.最好在關閉資料庫之前做查詢並結合V$RESOURCE_LIMIT檢視其它資源的使用.

prompt Reserved Pool High-Water-Mark Since Instance Startup

prompt ====================================================

select

sum(r.ksmchsiz) - &stopper reserved_size,

sum(

r.ksmchsiz -

decode(h.kghlunfu, 0, decode(r.indx, 1, r.ksmchsiz, 0), 0)

) - &stopper high_water_mark,

to_char(

100 * (sum(

r.ksmchsiz -

decode(h.kghlunfu, 0, decode(r.indx, 1, r.ksmchsiz, 0), 0)

) - 48

) / (sum(r.ksmchsiz) - &stopper),

'99999'

) || '%' " USAGE"

from

sys.x_$kghlu h,

sys.x_$ksmspr r

where

h.inst_id = userenv('Instance') and

r.inst_id = userenv('Instance')

/

prompt

RESERVED_SIZE HIGH_WATER_MARK USAGE

------------- --------------- -------

256000 15080 6%

Marking Objects for Keeping:

在 一個SIZE適當的SHARED POOL, dead Chunks是不會被清除出去的.任何一個清除的動作都意味著一些有用的物件也會被清除掉的危險.特別是可重建的物件,因為它們只在一定時間內才被使用, 但是在它們被重建時的代價可能會很大,因為它們可能是一個很大的物件或者需要更復雜的處理程式.

減輕這個危險性的辦法就是用DBMS_SHARED_POOL.KEEP將一些使用者自己認為有用的物件KEEP到SHARED POOL中.這個程式將物件以及有關的下級物件放在library cache中並將它們標誌為是KEEP在SHARED POOL中的.所以最合適做這個的時間是在例項啟動之後做KEEP操作以免SHARED POOL產生更多的碎片.經常會錯誤的認為如包等大的物件不需要KEEP到SHARED POOL中,因為它們一般會被放到SHARED POOL的RESERVED部分,因此被清除的機率非常小.其實不然,很多大的物件實際上是以多個小的Chunks來分配SHARED POOL記憶體的,是沒辦法以它們的大小來獲得特殊的保護.透過檢視錶X$KSMLRU可以確認哪些library cache物件需要KEEP到SHARED POOL中.

Flushing the Shared Pool:

接 合連續的free chunks的唯一方法就是用命令ALTER SYSTEM FLUSH SHARED POOL顯示的清空SHARED POOL.在實踐中,清空SHARED POOL會減少shared pool latch競爭,也會降低產生ORA-4031錯誤機率,也會減少即刻的效能競爭,特別是那些被KEEP到SHARED POOL中的主要物件.反之,如果那些主物件都已經KEEP到SHARED POOL中了,而且你的SHARED POOL SIZE比較適當,就要少使用FLUSH SHARED POOL,否則,例項將會在正常的執行時間對系統效能的要求特別大.

一 般地,會在晚上備份完之後來做FLUSH SHARED POOL.其它的時間就是在SHARED POOL有很多的碎片或者空間不足.在做FLUSH SHARED POOL時要確認不要對CAHED SEQUENCE產生不必要的缺口.要達到這個目的可以將SEQUENCE KEEP到SHARED POOL中,如果是單個例項也可以臨時的執行ALTER SEQUENCE NOCACHE.可用下面的PROCEDURE來確認哪些SEQUENCE需要KEEP到SHRAED POOL中.如果需要做SHUTDOWN ABORT來關閉資料庫時最好先將SEQUENCE KEEP到SHARED POOL中.

declare

cursor cached_sequences is

select

sequence_owner,

sequence_name

from

sys.dba_sequences

where

cache_size > 0;

sequence_owner varchar2(30);

sequence_name varchar2(30);

begin

open cached_sequences;

loop

fetch cached_sequences into sequence_owner, sequence_name;

exit when cached_sequences%notfound;

sys.dbms_shared_pool.keep(sequence_owner || '.' || sequence_name, 'Q');

end loop;

end;

/

Heaps and Subheaps

針 對SHARED POOL的FIXED TABLES X$是以KSM和KGH開頭,它們分別代表的意思是Oracle記憶體管理器和堆管理器模型.兩者是緊密聯絡在一起工作的.記憶體管理器是負責與作業系統OS 進行互動以獲得記憶體供Oracle使用和記憶體分配資訊.堆管理器則是進行動態的記憶體分配和管理.SHARED POOL也叫SGA HEAP就是這個原因了.

一個堆包含堆描述器和一個或多個記憶體區,當然也包含子堆.在這種情 況下,子堆的堆描述器和記憶體區是以父堆的Chunks來分配的.HEAP的大小是以HEAP的型別和HEAP’S FREE LIST和LRU LIST的LIST頭資訊的不同而不同的.每個記憶體區都有頭部資訊指向前面的和後面的一個堆,還有此HEAP還有多少空間可分配的資訊.

除 了Reserved部分,SHARED POOL的子堆實際上跟SHARED POOL本身有相同的結構.記憶體是以Chunks分配的,Free Chunks被組織成Free Lists. Unpinned Recreatable Chunks也是被組織成兩個LRU LISTS: Transient chunks和Recurrent chunks.子堆也有永久性的記憶體Chunks.也可以再包含子堆,深度為4.

CACHED 在SHARED POOL的大部分物件實際上都是在子堆裡面為一個新的Chunks查詢空間,就好象是SHARED POOL自己為一個新的Chunks查詢空間.所不同的是,子堆是以區來增長的,而SHARED POOL是一個固定大小的SIZE.子堆新區是以最小SIZE的區(適合物件的Chunks的最小SIZE)來分配的,所以它一般會找最小的 Chunks.

The Large Pool:

如果引數LARGE_POOL_SIZE有設定,則Large Pool將會在SGA中的變數區域(variable area)被配置為一個單獨的堆.它不是SHARED POOL的一部分,是以large memory latch來保護的. Large Pool只包含空閒的Chunks和可釋放的Chunks.不包含Recreatable Chunks,所以堆管理器的LRU機制是不被使用的.

為了阻止在Large Pool中產生碎片,所有的Large Pool Chunks的SIZE一般都以引數_LARGE_POOL_MIN_ALLOC做為其SIZE,其預設值為16K.這個引數不必要做調優.

在下列情況下建議你設定LARGE_POOL_SIZE引數使用Large Pool:

使用了MTS

使用了Recovery Manager(RMAN)

使用了並行的查詢選項Parallel Query Option(PQO)

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/18921899/viewspace-1017271/,如需轉載,請註明出處,否則將追究法律責任。

相關文章