1. 程式人生 > >buffer cache 和shared pool 詳解(之三,shared pool原理)

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檢視查詢

;至於Data Dictionary  Cache主要用於存放資料字典資訊,包括表、檢視等物件的結構資訊,使用者以及物件許可權資訊,這部分資訊相對穩定,在Shared  Pool中通過字典快取單獨存放,字典快取的內容是按行(Row)儲存的(其他資料通常按Buffer儲存),所以又被稱為Row Cache,其資訊可以通過V$ROWCACHE查詢。

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_MEMORYdisplays all the memory blocks and their status.

Column

Datatype

Description

ID

NUMBER

Unique block identifier (that is, the block number)

CHUNK

NUMBER

Chunk to which the block belongs (the upper 27 bits of the ID)

OFFSET

NUMBER

Offset of the block within its chunk (the lower 5 bits of the ID)

FREE

VARCHAR2(3)

Indicates whether the block is free (YES) or not (NO)

OBJECT_ID

NUMBER

Cache object to which the memory block belongs; NULL if the memory block is not allocated to a cache object (FREE = YES)

POSITION

NUMBER

Position of the block in the cached object; NULL if the memory block is not allocated to a cache object (FREE = YES)

通過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:

  • Result
  • Dependency

STATUS

VARCHAR2(9)

Status of the object:

  • New - Result is still under construction
  • Published - Result is available for use
  • Bypass - Result will be bypassed from use
  • Expired - Result has exceeded expiration time
  • Invalid - Result is no longer available for use

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:

  • SQL
  • PLSQL

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:

  • YES: If the result cache object references a remote database object
  • NO: If the result cache object does not reference a remote database object

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的執行機制仍然是十分重要的。