Oracle SHARED POOL的SUB POOL技术
从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.