buffer cache 和shared pool 詳解(之三,shared pool原理)
【深入解析--eygle】 學習筆記
1.2 shared pool原理
Shared Pool是Oracle SGA設定中最複雜也是最重要的一部分內容,Oracle通過Shared Pool來實現SQL共享、減少程式碼硬解析等,從而提高資料庫的效能。在某些版本中,如果設定不當,Shared Pool可能會極大影響資料庫的正常執行。
在Oracle 7之前,Shared Pool並不存在,每個Oracle連線都有一個獨立的Server程序與之相關聯,Server程序負責解析和優化所有SQL和PL/SQL程式碼。典型的,在OLTP環境中,很多程式碼具有相同或類似的結構,反覆的獨立解析浪費了大量的時間以及資源,Oracle最終認識到這個問題,並且從PL/SQL開始嘗試把這部分可共享的內容進行獨立儲存和管理,於是Shared Pool作為一個獨立的SGA元件開始被引入,並且其功能和作用被逐漸完善和發展起來。
在這裡注意到,Shared Pool最初被引入的目的,也就是它的本質功能在於實現共享。如果使用者的系統程式碼是完全異構的(假設程式碼從不繫結變數,從不反覆執行),那麼就會發現,這時候Shared Pool完全就成為了一個負擔,它在徒勞無功地進行無謂的努力:儲存程式碼、執行計劃等期待重用,並且客戶端要不停的獲取Latch,試圖尋找共享程式碼,卻始終一無所獲。如果真是如此,那這是我們最不願看到的情況,Shared Pool變得有害無益。當然這是極端,可是在效能優化中我們發現,大多數效能低下的系統都存在這樣的通病:程式碼極少共享,缺乏或從不實行變數繫結。優化這些系統的根本方法就是優化程式碼,使程式碼(在保證效能的前提下)可以充分共享,減少無謂的反覆硬/軟解析。
實際上,Oracle引入Shared Pool就是為了幫助我們實現程式碼的共享和重用。瞭解了這一點之後,我們在應用開發的過程中,也應該有意識地ᨀ高自己的程式碼水平,以期減少資料庫的壓力。這應該是對開發人員最基本的要求。
Shared Pool主要由兩部分組成,一部分是庫快取(Library Cahce),另一部分是資料字典快取(Data Dictionary Cache)。Library Cache主要用於儲存SQL語句、SQL語句相關的解析樹、執行計劃、PL/SQL程式塊(包括匿名程式塊、儲存過程、包、函式等)以及它們轉換後能夠被Oracle執行的程式碼等,這部分資訊可以通過v$librarycache檢視查詢
17:44:15 [email protected] SQL>desc v$librarycache;
Name Null? Type
---------------------------- ---------------------------------
NAMESPACE VARCHAR2(64)
GETS NUMBER
GETHITS NUMBER
GETHITRATIO NUMBER
PINS NUMBER
PINHITS NUMBER
PINHITRATIO NUMBER
RELOADS NUMBER
INVALIDATIONS NUMBER
DLM_LOCK_REQUESTS NUMBER
DLM_PIN_REQUESTS NUMBER
DLM_PIN_RELEASES NUMBER
DLM_INVALIDATION_REQUESTS NUMBER
DLM_INVALIDATIONS NUMBER
17:44:40 [email protected] SQL>
17:44:40 [email protected] SQL>desc v$rowcache;
Name Null? Type
------------------------------ -------------------------------
CACHE# NUMBER
TYPE VARCHAR2(11)
SUBORDINATE# NUMBER
PARAMETER VARCHAR2(32)
COUNT NUMBER
USAGE NUMBER
FIXED NUMBER
GETS NUMBER
GETMISSES NUMBER
SCANS NUMBER
SCANMISSES NUMBER
SCANCOMPLETES NUMBER
MODIFICATIONS NUMBER
FLUSHES NUMBER
DLM_REQUESTS NUMBER
DLM_CONFLICTS NUMBER
DLM_RELEASES NUMBER
17:50:55 [email protected] SQL>
下圖說明了Shared Pool各個部分協同工作以及與Buffer Cache的配合。
從Oracle Database 11g開始,在Shared Pool中劃出了另外一塊記憶體用於儲存SQL查詢的結果集,稱為ResultCache Memory。以 前Shared Pool的主要功能是共享SQL,減少硬解析,從而ᨀ高效能,但是SQL共享之後,執行查詢同樣可能消耗大量的時間和資源,現在Oracle嘗試將查詢的結果集快取起來,如果同一SQL或PL/SQL函式多次執行(特別是包含複雜運算的SQL), 那 麼 緩 存 的查 詢 結 果 可 以 直 接 返 回給使用者,不需要真正去執行運算,這樣就又為效能帶來了極大的提升。
1.2.1 Oracle 11g 新特性:Result Cache
結果集快取(Result Cache)是Oracle Database 11g新引入的功能,除了可以在伺服器端快取結果集(ServerResult Cache)之外,還可以在客戶端快取結果集(Client Result Cache)。
伺服器端的Result Cache Memory由兩部分組成:
(1) SQL Query Result Cache:儲存SQL查詢的結果集。
(2) PL/SQL Function Result Cache:用於儲存PL/SQL函式的結果集。
Oracle通過一個新引入初始化引數result_cache_max_size 來控制該Cache的大小。如果result_cache_max_size=0 則表示禁用該特性。引數result_cache_max_result 則控制單個快取結果可以佔總的ServerResult Cache大小的百分比。
09:47:20 [email protected] SQL>show parameter result_
NAME TYPE VALUE
---------------------------------------------------------- ------------------------------
client_result_cache_lag big integer 3000
client_result_cache_size big integer 0
result_cache_max_result integer 5
result_cache_max_size big integer 1M
result_cache_mode string MANUAL
result_cache_remote_expiration integer 0
09:48:09 [email protected] SQL>
上面顯示的引數中result_cache_mode用於控制Server result cache的模式,該引數有3個可選設定。
(1) 設定auto:則優化器會自動判斷是否將查詢結果快取。
(2) 設定manual:則需要通過查詢提示result_cache來告訴優化器是否快取結果。
(3) 設定force :則儘可能地快取查詢結果(通過提示no_result_cache可以拒絕快取)
09:52:31 [email protected] SQL>create table felix asselect * from dba_objects;
Table created.
09:53:28 [email protected] SQL>alter systemflush SHARED_POOL;
System altered.
09:53:42 [email protected] SQL>alter system flushBUFFER_CACHE;
System altered.
09:54:06 [email protected] SQL>set autot on;
09:54:25 [email protected] SQL>select count(*) fromfelix;
COUNT(*)
----------
75613
Execution Plan
----------------------------------------------------------
Plan hash value: 2587295606
--------------------------------------------------------------------
| Id |Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------
| 0 |SELECT STATEMENT | | 1 | 301 (1)| 00:00:04 |
| 1 | SORTAGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| FELIX | 63221 | 301 (1)| 00:00:04 |
--------------------------------------------------------------------
Note
-----
- dynamicsampling used for this statement (level=2)
Statistics
----------------------------------------------------------
70 recursive calls
0 db block gets
1167 consistent gets
1351 physical reads
0 redo size
528 bytes sent via SQL*Net to client
523 bytes received via SQL*Netfrom client
2 SQL*Net roundtrips to/fromclient
5 sorts (memory)
0 sorts (disk)
1 rows processed
09:54:44 [email protected] SQL>
現在再來看看在Server Result Cache下Oracle的行為,首先在result_cache_mode引數設定為MANUAL時:
09:56:02 [email protected] SQL>show parameterresult_cache_mode
NAME TYPE VALUE
------------------------------------ -----------------------------------
result_cache_mode string MANUAL
09:56:50 [email protected] SQL>
需要在SQL語句中手工指定Cache,這需要通過加入一個hints來實現,這個hints是result_cache:
09:56:50 [email protected] SQL>select /*+result_cache */ count(*) from felix;
COUNT(*)
----------
75613
Execution Plan
----------------------------------------------------------
Plan hash value: 2587295606
------------------------------------------------------------------------------------------
| Id |Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 |SELECT STATEMENT | | 1 | 301 (1)| 00:00:04 |
| 1 | RESULT CACHE | 1hnnwscv2aj3631n497zczt04j | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | TABLE ACCESS FULL| FELIX | 63221 | 301 (1)| 00:00:04 |
------------------------------------------------------------------------------------------
Result Cache Information (identified by operationid):
------------------------------------------------------
1 -column-count=1; dependencies=(SCOTT.FELIX); attributes=(single-row);name="select /*+ result_cache */ count(*) from felix"
Note
-----
- dynamicsampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
1137 consistent gets
1077 physical reads
0 redo size
528 bytes sent via SQL*Net toclient
523 bytes received via SQL*Netfrom client
2 SQL*Net roundtrips to/fromclient
0 sorts (memory)
0 sorts (disk)
1 rows processed
09:58:49 [email protected] SQL>
注意到這個執行計劃已經和以往的不同,RESULTCACHE以1hnnwscv2aj3631n497zczt04j名稱建立。那麼在接下來的查詢中,這個Result Cache就可以被利用:
09:58:49 [email protected] SQL>select /*+result_cache */ count(*) from felix;
COUNT(*)
----------
75613
Execution Plan
----------------------------------------------------------
Plan hash value: 2587295606
------------------------------------------------------------------------------------------
| Id |Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 |SELECT STATEMENT | | 1| 301 (1)| 00:00:04 |
| 1 | RESULT CACHE | 1hnnwscv2aj3631n497zczt04j | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | TABLE ACCESS FULL| FELIX | 63221 | 301 (1)| 00:00:04 |
------------------------------------------------------------------------------------------
Result Cache Information (identified by operationid):
------------------------------------------------------
1 - column-count=1;dependencies=(SCOTT.FELIX); attributes=(single-row); name="select /*+result_cache */ count(*) from felix"
Note
-----
- dynamicsampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
528 bytes sent via SQL*Net toclient
523 bytes received via SQL*Netfrom client
2 SQL*Net roundtrips to/fromclient
0 sorts (memory)
0 sorts (disk)
1 rows processed
10:01:08 [email protected] SQL>
在這個利用到Result Cache的查詢中,consistent gets減少到0,直接訪問結果集,不再需要執行SQL查詢。這就是Result Cache的強大之處。
在以上測試中,當result_cache_mode設定為MANUAL時,只有使用hints的情況下,Oracle才會利用快取結果集;而如果將result_cache_mode設定為AUTO,Oracle如果發現緩衝結果集已經存在,那麼就會自動使用。但是如果緩衝結果集不存在,Oracle並不會自動進行緩衝,只有使用HINT的情況下,Oracle才會將執行的結果集快取。
可以通過查詢v$result_cache_memory檢視來看Cache的使用情況:
10:05:07 [email protected] SQL>select * fromV$RESULT_CACHE_MEMORY where free='NO';
ID CHUNK OFFSET FREE OBJECT_ID POSITION
---------- ---------- ---------- ------ --------------------
0 0 0 NO 0 0
1 0 1 NO 1 0
10:05:12 [email protected] SQL>
V$RESULT_CACHE_MEMORY
V$RESULT_CACHE_MEMORY
displays all the memory blocks and their status.
Column |
Datatype |
Description |
|
|
Unique block identifier (that is, the block number) |
|
|
Chunk to which the block belongs (the upper 27 bits of the ID) |
|
|
Offset of the block within its chunk (the lower 5 bits of the ID) |
|
|
Indicates whether the block is free ( |
|
|
Cache object to which the memory block belongs; NULL if the memory block is not allocated to a cache object ( |
|
|
Position of the block in the cached object; NULL if the memory block is not allocated to a cache object ( |
通過V$RESULT_CACHE_STATISTICS可以查詢Result Cache的統計資訊:
10:15:27 [email protected] SQL>select * fromV$RESULT_CACHE_STATISTICS;
IDNAME VALUE
-------------------------------------------------- ------------------------
1 Block Size (Bytes) 1024
2Block Count Maximum 1024
3Block Count Current 32
4Result Size Maximum (Blocks) 51
5Create Count Success 1
6Create Count Failure 0
7Find Count 1
8Invalidation Count 0
9Delete Count Invalid 0
10Delete Count Valid 0
11Hash Chain Length 1
12Find Copy Count 1
12 rows selected.
10:15:34 [email protected] SQL>
V$RESULT_CACHE_OBJECTS記錄了Cache的物件:
10:20:54 [email protected] SQL>SELECT ID,TYPE,NAME,BLOCK_COUNT,ROW_COUNTFROM V$RESULT_CACHE_OBJECTS;
IDTYPE NAME BLOCK_COUNT ROW_COUNT
---------- ------------------------------------------------------------ ----------- ----------
0Dependency SCOTT.FELIX 1 0
1Result select /*+result_cache */ count(*) from 1 1
felix
10:21:19 [email protected] SQL>
V$RESULT_CACHE_OBJECTS displays all theobjects (both cached results and dependencies) and their attributes.
Column |
Datatype |
Description |
ID |
NUMBER |
Identifier for the cache object (also the ID of the first block) |
TYPE |
VARCHAR2(10) |
Type of the cache object:
|
STATUS |
VARCHAR2(9) |
Status of the object:
|
BUCKET_NO |
NUMBER |
Internal hash bucket for the object |
HASH |
NUMBER |
Hash value for the object |
NAME |
VARCHAR2(128) |
Name (for example, SQL prefix or PL/SQL function name) |
NAMESPACE |
VARCHAR2(5) |
Namespace:
|
CREATION_TIMESTAMP |
DATE |
Time when the object was created |
CREATOR_UID |
NUMBER |
UID that created the object |
DEPEND_COUNT |
NUMBER |
Number of dependencies (TYPE = Result) or dependents (TYPE = Dependency) |
BLOCK_COUNT |
NUMBER |
Total number of blocks in the cached object |
SCN |
NUMBER |
Build SCN (TYPE = Result) or invalidation SCN (TYPE = Dependency) |
COLUMN_COUNT |
NUMBER |
Number of columns in the cached resultFoot 1 |
PIN_COUNT |
NUMBER |
Number of active scans on this resultFootref 1 |
SCAN_COUNT |
NUMBER |
Total number of scans initiated on the cached resultFootref 1 |
ROW_COUNT |
NUMBER |
Total number of rows in the cached resultFootref 1 |
ROW_SIZE_MAX |
NUMBER |
Size of the largest row (in bytes)Footref 1 |
ROW_SIZE_MIN |
NUMBER |
Size of the smallest row (in bytes)Footref 1 |
ROW_SIZE_AVG |
NUMBER |
Average size of a row (in bytes)Footref 1 |
BUILD_TIME |
NUMBER |
Amount of time (in hundredths of a second) it took to build the cached resultFootref 1 |
LRU_NUMBER |
NUMBER |
LRU list position (the smaller the value, the more recent the usage)Footref 1 |
OBJECT_NO |
NUMBER |
Dictionary object number of the dependency objectFoot 2 |
INVALIDATIONS |
NUMBER |
Number of times the object has invalidated its dependentsFootref 2 |
SPACE_OVERHEAD |
NUMBER |
Overhead (in bytes) for the resultFootref 1 |
SPACE_UNUSED |
NUMBER |
Unused space (in bytes) for the resultFootref 1 |
CACHE_ID |
VARCHAR2(93) |
CacheId for the result (object name if it's a dependency) |
CACHE_KEY |
VARCHAR2(93) |
CacheKey for the result (object name if it's a dependency) |
DB_LINKFoot 3 |
VARCHAR2(3) |
Possible values:
|
NUMBER |
Checksum for the result object. The checksum is computed over all the blocks in the result cache object minus the object header. |
Footnote 1 These columns are only valid for TYPE = Result; otherwise, they are NULL.
Footnote 2 These columns are only valid for TYPE = Dependency; otherwise, they are NULL.
Footnote 3 This column is available starting with Oracle Database11g Release 2 (11.2.0.4)
Table 7-6 Views and TablesRelated to the Server and Client Result Caches
View/Table |
Description |
V$RESULT_CACHE_STATISTICS |
Lists various server result cache settings and memory usage statistics. |
V$RESULT_CACHE_MEMORY |
Lists all the memory blocks in the server result cache and their corresponding statistics. |
V$RESULT_CACHE_OBJECTS |
Lists all the objects whose results are in the server result cache along with their attributes. |
V$RESULT_CACHE_DEPENDENCY |
Lists the dependency details between the results in the server cache and dependencies among these results. |
CLIENT_RESULT_CACHE_STATS$ |
Stores cache settings and memory usage statistics for the client result caches obtained from the OCI client processes. This statistics table has entries for each client process that is using result caching. After the client processes terminate, the database removes their entries from this table. The client table lists information similar to V$RESULT_CACHE_STATISTICS. See Also: Oracle Database Reference for details about CLIENT_RESULT_CACHE_STATS$ |
DBA_TABLES, USER_TABLES, ALL_TABLES |
Includes a RESULT_CACHE column that shows the result cache mode annotation for the table. If the table has not been annotated, then this column shows DEFAULT. This column applies to both server and client result caching. |
一個新的系統包被引入,DBMS_RESULT_CACHE可以用於執行關於Result Cache的管理:
10:21:[email protected] SQL>set serveroutput on
10:25:30 [email protected] SQL>execdbms_result_cache.memory_report
R e s u l t C a c h e M e m o r y R e p o r t
[Parameters]
Block Size = 1K bytes
Maximum Cache Size = 1M bytes (1K blocks)
Maximum Result Size = 51K bytes (51 blocks)
[Memory]
Total Memory = 165032 bytes [0.096% of the SharedPool]
... Fixed Memory = 5352 bytes [0.003% of theShared Pool]
... Dynamic Memory = 159680 bytes [0.093% of theShared Pool]
....... Overhead = 126912 bytes
....... Cache Memory = 32K bytes (32 blocks)
........... Unused Memory = 30 blocks
........... Used Memory = 2 blocks
............... Dependencies = 1 blocks (1 count)
............... Results = 1 blocks
................... SQL = 1blocks (1 count)
PL/SQL procedure successfully completed.
10:25:49 [email protected] SQL>
1.2.2 Shared Pool 的設定說明
Shared Pool的大小可以通過初始化引數shared_pool_size設定。在Oracle 10g之前在共享池的設定上存在很多不同聲音,一方面很多人建議可以把Shared Pool設定得稍大,以充分Cache程式碼和避免ORA-04031錯誤的出現;另一方面又有很多人建議不能把Shared Pool設定得過大,因為過大可能會帶來管理上的額外負擔,從而會影響資料庫的效能。
在下面的測試中用到了Shared Pool的轉儲,所以首先需要了解一下相關的命令。可以通過如下命令轉儲Shared Pool共享記憶體的內容:
注意alter session setevents 'immediate trace name heapdump level 2'是一條內部命令,指定Oracle把Shared Pool的記憶體結構在Level 2級轉儲出來
Get_trc_scripts.sql
SELECT a.VALUE || b.symbol || c.instance_name ||'_ora_' || d.spid ||
'.trc' trace_file_name
FROM(SELECT VALUE FROM v$parameter WHERE NAME = 'user_dump_dest') a,
(SELECT SUBSTR(VALUE, -6, 1) symbol
FROM v$parameter
WHERE NAME = 'user_dump_dest') b,
(SELECT instance_name FROM v$instance) c,
(SELECT spid
FROM v$session s, v$process p, v$mystat m
WHERE s.paddr = p.addr
AND s.SID = m.SID
AND m.statistic# = 0) d;
TRACE_FILE_NAME
---------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/felix/felix/trace/felix_ora_2751.trc
10:36:03 [email protected] SQL>
Shared Pool通過Free Lists管理free記憶體塊(Chunk),Free的記憶體塊(Chunk)按 不 同size被劃分到不同的部分(Bucket)進行管理;
可以通過下圖對Shared Pool的Free List管理進行說明
不同bucket管理的記憶體塊的size範圍如下所示(size顯示的是下邊界):
[[email protected]~]$ cat /u01/app/oracle/diag/rdbms/felix/felix/trace/felix_ora_2751.trc | grepbucket
Reservedbucket 0 size=32
Reservedbucket 1 size=4400
Reservedbucket 2 size=8216
Reservedbucket 3 size=8696
Reservedbucket 4 size=8704
Reservedbucket 5 size=8712
Reservedbucket 6 size=8720
Reservedbucket 7 size=9368
Reservedbucket 8 size=9376
Reservedbucket 9 size=12352
Reservedbucket 10 size=12360
Reservedbucket 11 size=16408
Reservedbucket 12 size=32792
Reservedbucket 13 size=65560
Reservedbucket 14 size=1990644
Chunk 0788db800 sz= 968 freeable "vproblem_bucket"
Chunk 0788dbde8 sz= 872 freeable "vproblem_bucket"
Chunk 0788dc370 sz= 872 freeable "vproblem_bucket"
Reservedbucket 0 size=32
Reservedbucket 1 size=4400
Reservedbucket 2 size=8216
Reservedbucket 3 size=8696
Reservedbucket 4 size=8704
Reservedbucket 5 size=8712
Reservedbucket 6 size=8720
Reservedbucket 7 size=9368
Reservedbucket 8 size=9376
Reservedbucket 9 size=12352
Reservedbucket 10 size=12360
Reservedbucket 11 size=16408
Reservedbucket 12 size=32792
Reservedbucket 13 size=65560
Reservedbucket 14 size=1990644
Reservedbucket 0 size=32
Reservedbucket 1 size=4400
Reservedbucket 2 size=8216
Reservedbucket 3 size=8696
Reservedbucket 4 size=8704
Reservedbucket 5 size=8712
Reservedbucket 6 size=8720
Reservedbucket 7 size=9368
Reservedbucket 8 size=9376
Reservedbucket 9 size=12352
Reservedbucket 10 size=12360
Reservedbucket 11 size=16408
Reservedbucket 12 size=32792
Reservedbucket 13 size=65560
Reservedbucket 14 size=1990644
Reservedbucket 0 size=32
Reservedbucket 1 size=4400
Reservedbucket 2 size=8216
Reservedbucket 3 size=8696
Reservedbucket 4 size=8704
Reservedbucket 5 size=8712
Reservedbucket 6 size=8720
Reservedbucket 7 size=9368
Reservedbucket 8 size=9376
Reservedbucket 9 size=12352
Reservedbucket 10 size=12360
Reservedbucket 11 size=16408
Reservedbucket 12 size=32792
Reservedbucket 13 size=65560
Reservedbucket 14 size=1990644
[[email protected] ~]$
初始地,資料庫啟動以後,Shared Pool多數是連續記憶體塊。但是當空間分配使用以後,記憶體塊開始被分割,碎片開始出現,Bucket列表開始變長。
Oracle請求Shared Pool空間時,首先進入相應的Bucket進行查詢。如果找不到,則轉向下一個非空的Bucket,獲取第一個Chunk。分割這個Chunk,剩餘部分會進入相應的Bucket,進一步增加碎片
最終的結果是,由於不停分割,每個Bucket上的記憶體塊會越來越多,越來越碎小。通常Bucket 0的問題會最為顯著,在這個測試資料庫上,Bucket 0上的碎片已經達到9030個,而shared_pool_size設定僅為150MB。
通常如果每個Bucket上的Chunk多於2000個,就被認為是Shared Pool碎片過多。Shared Pool的碎片過多,是Shared Pool產生效能問題的主要原因。
碎片過多會導致搜尋Free Lists的時間過長,而我們知道,Free Lists的管理和搜尋都需要獲得和持有一個非常重要的Latch,就 是Shared Pool Latch。Latch是Oracle資料庫內部提供的一種低階鎖,通過序列機制保護共享記憶體不被併發更新/修改所損壞。Latch的持有通常都非常短暫(通常微秒級),但是對於一個繁忙的資料庫,這個序列機制往往會成為極大的效能瓶頸。
如果Free Lists連結串列過長,搜尋這個Free Lists的時間就會變長,從而可能導致Shared Pool Latch被長時間持有,在一個繁忙的系統中,這會引起嚴重的Shared PoolLatch的競爭。在Oracle 9i之前,這個重要的Shared Pool Latch只有一個,所以長時間持有將會導致嚴重的效能問題。
1.2.3 Oracle 9i 子緩衝池的增強
從Oracle 9i開始,Shared Pool 可以被分割為多個子緩衝池(SubPool)進行管理,每個SubPool可以被看作是一個Mini Shared Pool,擁 有 自己 獨 立 的Free List、內 存 結 構 以 及LRU List。同時Oracleᨀ供多個Latch對各個子緩衝池進行管理,從而避免單個Latch的競爭(Shared Pool Reserved Area同樣進行分割管理)。SubPool最多可以有7個,Shared Pool Latch也從原來的一個增加到現在的7個。如果系統有4個或4個以上的CPU,並且SHARED_POOL_SIZE大於250MB,Oracle可以把Shared Pool分割為多個子緩衝池(SubPool)進行管理,在Oracle 9i中,每個SubPool至少為128MB。
Oracle 9i中多個子緩衝池的結構示意如圖所示:
以下查詢顯示的是為管理SubPool而新增的子Latch:
select addr, name, gets, misses, spin_gets
fromv$latch_children
where name = 'shared pool';
ADDR NAME GETS MISSES SPIN_GETS
-------------------------------------------------------- ---------- ---------- ----------
00000000601072A0 shared pool 24 0 0
0000000060107200 shared pool 24 0 0
0000000060107160 shared pool 24 0 0
00000000601070C0 shared pool 24 0 0
0000000060107020 shared pool 24 0 0
0000000060106F80 shared pool 24 0 0
0000000060106EE0 shared pool 325942 10 1
7 rows selected.
11:02:08 [email protected] SQL>
但是需要注意的是,雖然多緩衝池技術使Oracle可以管理更大的共享池,但是SubPool的劃分可能也會導致各分割槽之間的協調問題,甚至可能因為記憶體分散而出現ORA-04031錯誤。最常見的問題是某個子緩衝池(SubPool)可能出現過度使用,當新的程序仍然被分配到這個SubPool時,可能會導致記憶體請求失敗(而此時其他SubPool可能還有很多記憶體空間)。
select KSMCHIDX "SubPool",
'sgaheap(' || KSMCHIDX || ',0)' sga_heap,
ksmchcom ChunkComment,
decode(round(ksmchsiz / 1000),
0,
'0-1K',
1,
'1-2K',
2,
'2-3K',
3,
'3-4K',
4,
'4-5K',
5,
'5-6k',
6,
'6-7k',
7,
'7-8k',
8,
'8-9k',
9,
'9-10k',
'> 10K') "size",
count(*),
ksmchcls Status,
sum(ksmchsiz) Bytes
fromx$ksmsp
whereKSMCHCOM = 'free memory'
group byksmchidx,
ksmchcls,
'sga heap(' || KSMCHIDX || ',0)',
ksmchcom,
ksmchcls,
decode(round(ksmchsiz / 1000),
0,
'0-1K',
1,
'1-2K',
2,
'2-3K',
3,
'3-4K',
4,
'4-5K',
5,
'5-6k',
6,
'6-7k',
7,
'7-8k',
8,
'8-9k',
9,
'9-10k',
'> 10K');
因為子緩衝池存在的種種問題,從Oracle 10g開始,Oracle允許記憶體請求在不同SubPool之間進行切換(Switch),從而ᨀ高了請求成功的可能(但是顯然切換不可能是無限制的,所以問題仍然可能存在)。
8個子池都被使用,其Latch使用情況如下:
select child#, gets
fromv$latch_children
where name= 'shared pool'
order bychild#;
CHILD# GETS
---------- ----------
1 343101
2 24
3 24
4 24
5 24
6 24
7 24
7 rows selected.
11:42:25 [email protected] SQL>
1.2.4 Oracle 10g 共享池管理的增強
子緩衝池的分配的演算法很簡單:
(1)每個子緩衝池必須滿足一定的記憶體約束;
(2)每4顆CPU可以分配一個子緩衝池,最多7個。
在Oracle 9i中,每個SubPool至少128MB,在Oracle10g中,每個子緩衝池至少為256MB。如前所述,SubPool的數量可以通過_kghdsidx_count引數來控制,但是沒有引數可以顯示地控制SubPool的大小。
不管Oracle 9i中的128MB以及Oracle10g中的256MB,某些情況下,可能需要增加SubPool的大小。可以通過控制Shared Pool大小以及SubPool的數量來改變SubPool的大小。一些Bug以及內部測試表明500MB的SubPool可能會帶來更好的效能,所以從Oracle 11g開始,每個SubPool至少為512MB。
除大小控制之外,在Oracle 10g中,Oracle仍然對共享池的管理做出了進一步改進,那就是對單個子緩衝池進行進一步的細分。現在預設地,Oracle 10g會將單個緩衝池分割為會4個子分割槽進行管理(這可能是因為通常4顆CPU才分配一個SubPool),使用類似如上的方法在Oracle 10gR2中進行測試:
分析得到的日誌,當僅有一個子緩衝時,SharedPool被劃分為sga heap(1,0)~sgaheap(1,3)共4個子分割槽:
[[email protected]~]# cat /u01/app/oracle/diag/rdbms/felix/felix/trace/felix_ora_4324.trc | grep"sga heap"
HEAP DUMP heap name="sga heap" desc=0x60001190
HEAP DUMP heap name="sga heap(1,0)" desc=0x60053f70
HEAP DUMP heap name="sga heap(1,1)" desc=0x600557c8
HEAP DUMP heap name="sga heap(1,2)" desc=0x60057020
HEAP DUMP heap name="sga heap(1,3)" desc=0x60058878
[[email protected] ~]#
當使用兩個子緩衝時,Shared Pool則被劃分為8個子分割槽進行管理;
Oracle 10g中多緩衝池結構示意圖如下圖所示
通過一個內部表X$KGHLU([K]ernel [G]eneric memory [H]eap manager State of [L]R[U] OfUnpinned Recreatable chunks)可以查詢這些子緩衝池的分配:
11:59:29 [email protected] SQL>selectaddr,indx,kghluidx,kghludur,kghluops,kghlurcr from x$kghlu;
ADDR INDX KGHLUIDX KGHLUDUR KGHLUOPS KGHLURCR
---------------- ---------- ---------- -------------------- ----------
00007FA372851098 0 1 0 119290 4425
12:03:45 [email protected] SQL>
通過這一系列的演算法改進,Oracle中Shared Pool管理得以不斷增強,較好的解決了大Shared Pool的效能問題;Oracle 8i中,過大Shared Pool設定可能帶來的栓鎖爭用等效能問題在某種程度上得以解決。從Oracle10g開始,Oracle開始ᨀ供自動共享記憶體管理,使用該特性,使用者可以不必顯示設定共享記憶體引數,Oracle會自動進行分配和調整,雖然Oracle給我們提供了極大的便利,但是瞭解自動化後面的原理對於理解Oracle的執行機制仍然是十分重要的。