從Oracle 9i開始,SHARED POOL可以分為多個SUB POOL,其數量受以下幾個因素影響:
?系統CPU的數量。默認情況下,在Oracle中每4個CPU分配一個SUB POOL,最多不能超過7個。
?共享池的大小。SUB POOL的最小容量隨著Oracle版本的不同而不同
?隱含參數_kghdsidx_count值。
當數據庫啟動時,Oracle優先根據_kghdsidx_count隱含參數值設置SUBPOOL數量。通過DUMP HEAP可以觀察SUBPOOL的數量,以下為Oracle 9i的4個SUB POOL:
[ora9208@mcdbatest udump]$ grep "sga heap" ora9208_ora_13150.trc
HEAP DUMP heap name="sga heap" desc=0x5000002c
HEAP DUMP heap name="sga heap(1,0)" desc=0x5001ec7c
HEAP DUMP heap name="sga heap(2,0)" desc=0x50023974
HEAP DUMP heap name="sga heap(3,0)" desc=0x5002866c
HEAP DUMP heap name="sga heap(4,0)" desc=0x5002d364
從Oracle 10g開始,每個SUB POOL由4個SUB PARTITION組成,如下所示:
[ora11203@mcdbatest trace]$ grep "sga heap" ora11203_ora_13056.trc
HEAP DUMP heap name="sga heap" desc=0x200010b4
HEAP DUMP heap name="sga heap(1,0)" desc=0x2002c534
HEAP DUMP heap name="sga heap(1,1)" desc=0x2002d16c
HEAP DUMP heap name="sga heap(1,2)" desc=0x2002dda4
HEAP DUMP heap name="sga heap(1,3)" desc=0x2002e9dc
HEAP DUMP heap name="sga heap(2,0)" desc=0x20031a5c
HEAP DUMP heap name="sga heap(2,1)" desc=0x20032694
HEAP DUMP heap name="sga heap(2,2)" desc=0x200332cc
HEAP DUMP heap name="sga heap(2,3)" desc=0x20033f04
HEAP DUMP heap name="sga heap(3,0)" desc=0x20036f84
HEAP DUMP heap name="sga heap(3,1)" desc=0x20037bbc
HEAP DUMP heap name="sga heap(3,2)" desc=0x200387f4
HEAP DUMP heap name="sga heap(3,3)" desc=0x2003942c
HEAP DUMP heap name="sga heap(4,0)" desc=0x2003c4ac
HEAP DUMP heap name="sga heap(4,1)" desc=0x2003d0e4
HEAP DUMP heap name="sga heap(4,2)" desc=0x2003dd1c
HEAP DUMP heap name="sga heap(4,3)" desc=0x2003e954
SUB PARTITION的出現跟SHARED POOL DURATION的特性有關,其特性由隱含參數_enable_shared_pool_durations決定,默認為TRUE,即啟用SHARED POOL DURATION特性。當_enable_shared_pool_durations被設置為FALSE時,SUB PARTITION在SUB POOL中消失。在Oracle 10g中,如果設置SGA_TARGET為0,或者在Oracle 10.2.0.5之前的版本中把cursor_space_for_time設置為TRUE時,_enable_shared_pool_durations自動被設置為FALSE。
每個SUB POOL擁有獨立的FREE LIST、LRU LIST和SHARED POOL LATCH。從這個角度來講,當系統有足夠的內存和CPU時,將SHARED POOL分為多個SUB POOL,能有效地減少SHARED POOL LATCH的爭用。可以通過以下查詢查看SHARED POOL LATCH的爭用情況:
SQL> select addr,name,gets,misses,spin_gets2 from v$latch_children 3 where name='shared pool';
ADDR NAME GETS MISSES SPIN_GETS
---------------- -------------------- --------------- ------- ---------
00000000600F5AE0 shared pool 70074401 26223 22238
00000000600F5B80 shared pool 107519850 45111 37757
00000000600F5C20 shared pool 58965575 20992 17791
00000000600F5CC0 shared pool 58675278 19808 16896
00000000600F5D60 shared pool 62756019 23706 20197
00000000600F5E00 shared pool 61585261 21257 18019
00000000600F5EA0 shared pool 84487594 29571 252337 rows selected.
可以通過查詢X$KSMSS([K]ernal [S]torage [M]emory Management [S]GA [S]tatistics (lengths) of SGA objects)內部視圖獲得每個SUBPOOL所分配的內存,如下所示:
SQL> SELECT 'shared pool('||NVL (DECODE (TO_CHAR (ksmdsidx),'0','0-Unused',ksmdsidx),'Total')||'):'subpool,2 SUM (ksmsslen) BYTES, ROUND (SUM (ksmsslen)/1048576,2) mb3 FROM x$ksmss WHERE ksmsslen > 04 GROUP BY ROLLUP (ksmdsidx) ORDER BY subpool ASC5 /SUBPOOL BYTES MB
-------------------- ---------- ----------
shared pool(1): 353587048 337.21
shared pool(2): 335554440 320.01
shared pool(3): 318773800 304.01
shared pool(4): 318773640 304.01
shared pool(5): 318773328 304.01
shared pool(6): 335549952 320.01
shared pool(7): 318773552 304.01
shared pool(Total): 2299785760 2193.258 rows selected.
另外,還可通過查詢X$KSMSS觀察各個子池的剩余內存。可以看到各個子池剩余內存約在25MB~42MB之間,但這些剩余內存可能是零散的碎片,如下所示:
SQL> SELECT subpool, NAME, SUM (BYTES), ROUND (SUM (BYTES) / 1048576, 2) mb2 FROM (SELECT 'shared pool (' || DECODE (TO_CHAR (ksmdsidx), '0', '0 - Unused', ksmdsidx)3 || '):' subpool, ksmssnam NAME, ksmsslen BYTES4 FROM x$ksmss WHERE ksmsslen > 0 5 AND LOWER (ksmssnam) LIKE LOWER ('%free memory%'))6 GROUP BY subpool, NAME ORDER BY subpool ASC, SUM (BYTES) DESC;SUBPOOL NAME SUM(BYTES) MB
-------------------- --------------- ---------- ----------
shared pool (1): free memory 36938752 35.23
shared pool (2): free memory 44230408 42.18
shared pool (3): free memory 42153816 40.2
shared pool (4): free memory 43584456 41.57
shared pool (5): free memory 27036848 25.78
shared pool (6): free memory 39586080 37.75
shared pool (7): free memory 37918416 36.167 rows selected.
值得注意的是,如果Oracle進程在某個SUB POOL中請求內存失敗,可能仍然會繼續在同一個SUB POOL中請求,所以過小的SUB POOL容量非常容易導致內存碎片,進而產生ORA-04031錯誤。雖然從Oracle 10g開始,Oracle改進了相關算法,允許進程請求內存時可在不同SUB POOL中切換,提高了請求成功的可能性,但需要說明的是,請求切換不是一個無止境操作,而且請求切換也需要額外的管理成本,降低了內存獲取的效率。
隨著硬件技術的快速發展,再加上Oracle已經意識到過小的SUB POOL容量帶來的問題,因此,從Oracle 10.2.0.3開始,SUB POOL的最小容量變為了512MB。所以我們并不能因為出現LATCH:SHARED POOL爭用而隨意增大_kghdsidx_count隱含參數。相反,在頻繁發生ORA-04031的系統中可能更需要適當減少SUB POOL的個數。過多的SUB POOL可能會額外增加Oracle在各SUB POOL之間的協調成本。通過查詢X$KGHLU([K]ernel [G]eneric memory [H]eap manager State of [L]R[U] of unpinned recreatable chunks)內部視圖可以觀察各SUBPOOL發生ORA-04031的情況:
SQL> column indx heading "indx|indx num"
SQL> column kghlurcr heading "RECURRENT|CHUNKS"
SQL> column kghlutrn heading "TRANSIENT|CHUNKS"
SQL> column kghlufsh heading "FLUSHED|CHUNKS"
SQL> column kghluops heading "PINS AND|RELEASES"
SQL> column kghlunfu heading "ORA-4031|ERRORS"
SQL> column kghlunfs heading "LAST ERROR|SIZE"
SQL> select2 indx,3 kghlurcr,4 kghlutrn,5 kghlufsh,6 kghluops,7 kghlunfu,8 kghlunfs9 from10 sys.x$kghlu11 where12 inst_id = userenv('Instance');indx RECURRENT TRANSIENT FLUSHED PINS AND ORA-4031 LAST ERRORindx num CHUNKS CHUNKS CHUNKS RELEASES ERRORS SIZE
---------- ---------- ---------- ---------- ---------- ---------- ----------0 21079 23947 199844842 1726517983 273 41121 32759 34703 181014058 1232596323 282 40802 33038 34934 182120171 1704173952 167 40803 27987 28540 182331413 2102763044 920 41124 37328 40418 201238783 2205809326 74 41605 30853 35079 202960194 2649732105 379 40806 27690 34344 200629415 2009369183 15 41927 rows selected.