Oracle Shared Pool 原理
Oracle Shared Pool 原理
由於shared pool中最重要的是library cache,所以本文主要講解Library cache的結構,library cache latch,library cache lock,library cache pin。
What is shared pool?
Shared pool是SGA中的一部分,由於它是SGA的一部分,這意味著它可以被所有的進程所訪問,Shared Pool當中主要包含了2部分:library cache和dictionary cache 也稱為 row cache。
Library cache包含了共享SQL區(shared SQL areas),私有SQL區(private SQLareas,如果配置了共享服務器),PL/SQL存儲過程以及包,還有一些控制信息,比如說locks以及library cache handles。
Dictionary cache包含了表,視圖的依賴信息,比如表結構,它的用戶,Oracle在解析SQL的時候就會頻繁的訪問dictionary cache。
How is it managed?
Shared pool和PGA都是由一個Oracle的內存管理器來管理,我們稱之為KGH heap manager。Heap Manager不是一個進程,而是一串代碼。Heap Manager主要目的就是滿足server 進程請求memory 的時候分配內存或者釋放內存。Heap Manager在管理PGA的時候,Heap Manager需要和操作系統來打交道來分配或者回收內存。但是呢,在shared pool中,內存是預先分配的,Heap Manager管理所有的空閑內存。當某個進程需要分配shared pool的內存的時候,Heap Manager就滿足該請求,Heap Manager也和其他ORACLE模塊一起工作來回收shared pool的空閑內存。
Library Cache Manager
Library cache Manager 可以看做是Heap Manager的客戶端,因為library cache manager是根據Heap Manager來分配內存從而存放library cache objects。Library cache Manager控制所有的library cache object,包括package/procedure, cursor, trigger等等。
Hash Table and Hash Bucket
Library cache是由一個hash table組成,這個hash table又由hash bucket組成的數組構成,每個hash bucket又是由一些相互指向的library cache handle所組成,library cache object handle就指向具體的library cache object以及一些引用列表。
Library Cache結構示意圖如下:
Library Cache handle
我們對Library cache中所有對象的訪問是通過利用library cache handle來實現的,也就是說我們想要訪問library cache object,我們必須先找到library cache handle。Library cache handle指向library cache object,它包含了library object的名字,命名空間,時間戳,引用列表,lock對象以及pin對象的列表信息等等。Library cache handle也被library cache用來記錄哪個用戶在這個這個handle上有lock,或者是哪個用戶正在等待獲得這個lock。那麽這裏我們也知道了library cache lock是發生在handle上的。
當一個進程請求library cache object, library cache manager就會應用一個hash 算法,從而得到一個hash 值,根據相應的hash值到相應的hash bucket中去尋找。這裏的hash算法原理與buffer cache中快速定位block的原理是一樣的。如果library cache object在內存中,那麽這個library cache handle就會被找到。有時候,當shared pool不夠大,library cache handle會保留在內存中,然而library cache heap由於內存不足被age out,這個時候我們請求的object heap就會被重載。最壞的情況下,library cache handle在內存中沒有找到,這個時候就必須分配一個新的library cache handle,同時object heap也會被加載到內存中。
Library Cache Object
Library Cache Object是由一些獨立的heap所組成,前面說了Library cache handle指向Library cache Object,其實handle是指向第一個heap,這個heap 我們就稱之為heap 0。Heap 0記錄了指向其他heap的指針信息。
根據上面描述,Library cache中的的Library cache object結構示意圖可以用上圖來表示(本圖摘自DSI405)
Library cache lock/pin
Library cache lock/pin是用來控制對library cache object的並發訪問的。Lock管理並發,pin管理一致性,lock是針對於library cache handle,而pin是針對於heap。
當我們想要訪問某個library cache object,我們首先要獲得這個指向這個object的handle的lock,獲得這個lock之後我們就需要pin住指向這個object的heap。
當我們對包,存儲過程,函數,視圖進行編譯的時候,Oracle就會在這些對象的handle上面首先獲得一個library cache lock,然後再在這些對象的heap上獲得pin,這樣就能保證在編譯的時候其它進程不會來更改這些對象的定義,或者將對象刪除。
當一個session對SQL語句進行硬解析的時候,這個session就必須獲得library cache lock,這樣其他session就不能夠訪問或者更改這個SQL所引用的對象。如果這個等待事件花了很長時間,通常表明共享池太小(由於共享池太小,需要搜索free的chunk,或者將某些可以被移出的object page out,這樣要花很長時間),當然了,也有可能另外的session正在對object進行修改(比如split 分區),而當前session需要引用那個table,那麽這種情況下我們必須等另外的session進行完畢。
Library Cache lock有3中模式:
-
Share(S): 當讀取一個library cache object的時候獲得
-
Exclusive(X): 當創建/修改一個library cache object的時候獲得
-
Null(N): 用來確保對象依賴性
比如一個進程想要編譯某個視圖,那麽就會獲得一個共享鎖,如果我們要create/drop/alter某個對象,那麽就會獲得exclusive lock。Null鎖非常特殊,我們在任何可以執行的對象(cursor,function)上面都擁有NULL鎖,我們可以隨時打破這個NULL鎖,當這個NULL鎖被打破了,就表示這個對象被更改了,需要重新編譯。NULL鎖主要的目的就是標記某個對象是否有效。比如一個SQL語句在解析的時候獲得了NULL 鎖,如果這個SQL的對象一直在共享池中,那麽這個NULL鎖就會一直存在下去,當這個SQL語句所引用的表被修改之後,這個NULL鎖就被打破了,因為修改這個SQL語句的時候會獲得Exclusive 鎖,
由於NULL鎖被打破了,下次執行這個SQL的時候就需要重新編譯。
Library Cache pin有2種模式:
-
Share(S): 讀取object heap
-
Exclusive(X):修改object heap
Library Cache pin沒有什麽好說的,當某個session想要讀取object heap,就需要獲得一個共享模式的pin,當某個session想要修改object heap,就需要獲得排他的pin。當然了在獲得pin之前必須獲得lock。
下面就是一個在Oracle10g RAC環境中的Library cache lock的案例
這個RAC環境有2個節點
[java] view plain copy- SQL> select inst_id from gv$instance;
- INST_ID
- ----------
- 2
- 1
- 在第一個節點中,session 4538被library cache lock阻塞
- SQL> select inst_id,sid,serial#,event ,p1raw,machine,status from gv$session where username=‘BX5685‘;
- INST_ID SID SERIAL# EVENT P1RAW MACHINE STATUS
- ---------- ---------- ---------- ------------------------ ------------ --------
- 1 4538 39833 library cache lock C000000346FBA458 bdhp4462 ACTIVE
- 在Node1上面查詢
- SQL> select * from dba_kgllock where kgllkreq > 0;
- KGLLKUSE KGLLKHDL KGLLKMOD KGLLKREQ KGLLKTYPE
- ---------------- ---------------- ---------- ---------- ------------
- C0000004789EF9D0 C000000346FBA458 0 2 Lock
- SQL> select kglnaown, kglnaobj from x$kglob where kglhdadr = ‘C000000346FBA458‘;
- KGLNAOWN KGLNAOBJ
- -------------------- --------------------
- IDWSU1 PROD_ASSOC_DNORM
- SQL> select kglhdadr, kglnaown, kglnaobj from x$kglob where kglnaobj = ‘PROD_ASSOC_DNORM‘ and KGLNAOWN=‘IDWSU1‘;
- KGLHDADR KGLNAOWN KGLNAOBJ
- ---------------- -------------------- --------------------
- C000000346FBA458 IDWSU1 PROD_ASSOC_DNORM
- 在Node2上面查詢
- SQL> select kglhdadr, kglnaown, kglnaobj from x$kglob where kglnaobj = ‘PROD_ASSOC_DNORM‘ and KGLNAOWN=‘IDWSU1‘;
- KGLHDADR KGLNAOWN KGLNAOBJ
- ------------------------------ -------------------- ------------------------------
- C000000443267070 IDWSU1 PROD_ASSOC_DNORM
- C00000035C33E248 IDWSU1 PROD_ASSOC_DNORM
- SQL> col event format a30
- select sid, serial#,s.event, sql_text from dba_kgllock w, v$session s, v$sqlarea a
- where w.kgllkuse = s.saddr and w.kgllkhdl=‘C000000443267070‘
- and s.sql_address = a.address
- and s.sql_hash_value = a.hash_value;SQL> 2 3 4
- SID SERIAL# EVENT SQL_TEXT
- ---------- ---------- ------------------------------
- 4774 36583 db file scattered read ALTER TABLE PROD_ASSOC_DNORM ENABLE CONSTRAINT PROD_ASSOC_DNORM_PK USING INDEX STORAGE ( INITIAL 4194304 NEXT 4194304 PCTINCREASE 0 ) TABLESPACE CDW_REFERENCE01M LOCAL
- 在Oracle10gR2中,library cache pin被library cache mutex 所取代
- Library cache Latch
Library cache latch用來控制對library cache object的並發訪問。前面已經提到,我們要訪問library cache object之前必須獲得library cache lock, lock不是一個原子操作(原子操作就是在操作程中不會被打破的操作,很明顯這裏的lock可以被打破),Oracle為了保護這個lock,引入了library cache latch機制,也就是說在獲得library cache lock之前,需要先獲得library cache latch,當獲得library cache lock之後就釋放library cache latch。
如果某個library cache object沒有在內存中,那麽這個lock就不能被獲取,這個時候需要獲得一個library cache load lock latch,然後再獲取一個library cache load lock,當load lock獲得之後就釋放library cache load lock latch。
我們來看一下在 Oracle10gR2 中的一個有關library cache latch,
library cache lock, library cache pin 的統計情況
SQL> select name,gets,misses,sleeps from v$latch where name like ‘%library%‘; NAME GETS MISSES SLEEPS ------------------------------ ---------- ---------- ---------- library cache 1937415298 5513866 2346346 library cache lock 734620587 425030 3021 library cache pin 171326029 108613 868 library cache pin allocation 2930490 35 1 library cache lock allocation 5226147 349 2 library cache load lock 720252 1762 34 library cache hash chains 0 0 0
library cache latch受隱含參數_KGL_LATCH_COUNT的控制,默認值為大於等於系統中CPU個數的最小素數,但是Oracle對其有一個硬性限制,該參數不能大於67。註意:我們去查詢_kgl_latch_count有時候顯示為0,這是一個bug。
那麽library cache object handle是由哪個子latch來保護的呢?Oracle利用下面算法來確定:
latch# = mod(bucket#, #latches)(摘自DSI405)
也就是說用哪個子latch去保護某個handle是根據那個handle所在的bucket號,以及總共有多少個子latch來進行hash運算得到的,對此我們不必深究。
latch contention
根據前面的講解,存在大量硬解析的系統上面就必然引發library cache latch, library cache lock競爭,下面就是一個每秒高達74個硬解析所引發
Library cache lock 成為Top wait event的一個案例。
Load Profile
Per Second |
Per Transaction |
|
Redo size: |
832,040.22 |
10,738.95 |
Logical reads: |
56,114.37 |
724.26 |
Block changes: |
5,897.48 |
76.12 |
Physical reads: |
3,442.07 |
44.43 |
Physical writes: |
174.41 |
2.25 |
User calls: |
273.48 |
3.53 |
Parses: |
82.02 |
1.06 |
Hard parses: |
74.53 |
0.96 |
Sorts: |
121.00 |
1.56 |
Logons: |
0.09 |
0.00 |
Executes: |
160.67 |
2.07 |
Transactions: |
77.48 |
Top 5 Timed Events
Event |
Waits |
Time(s) |
Avg Wait(ms) |
% Total Call Time |
Wait Class |
library cache lock |
3,603 |
10,588 |
2,939 |
51.7 |
Concurrency |
CPU time |
7,059 |
34.5 |
|||
db file sequential read |
1,454,620 |
1,932 |
1 |
9.4 |
User I/O |
db file scattered read |
863,507 |
1,178 |
1 |
5.7 |
User I/O |
log file parallel write |
269,164 |
260 |
1 |
1.3 |
System I/O |
如果shared pool過小,也會引發library cache latch競爭,與此同時還會伴隨shared pool latch競爭。下面就是一個由於shared pool過小,導致library cache latch成為top wait event的案例
Load Profile
Per Second |
Per Transaction |
|
Redo size: |
81,060.24 |
32,559.33 |
Logical reads: |
11,204.65 |
4,500.55 |
Block changes: |
414.99 |
166.69 |
Physical reads: |
0.50 |
0.20 |
Physical writes: |
5.62 |
2.26 |
User calls: |
189.05 |
75.93 |
Parses: |
38.51 |
15.47 |
Hard parses: |
3.58 |
1.44 |
Sorts: |
24.27 |
9.75 |
Logons: |
0.02 |
0.01 |
Executes: |
85.29 |
34.26 |
Transactions: |
2.49 |
Top 5 Timed Events
Event |
Waits |
Time(s) |
Avg Wait(ms) |
% Total Call Time |
Wait Class |
CPU time |
6,663 |
61.0 |
|||
latch: library cache |
1,306 |
157 |
120 |
1.4 |
Concurrency |
latch: shared pool |
5,527 |
152 |
28 |
1.4 |
Concurrency |
log file parallel write |
81,192 |
122 |
2 |
1.1 |
System I/O |
log file sync |
74,187 |
120 |
2 |
1.1 |
Commit |
Shared Pool Advisory
-
SP: Shared Pool Est LC: Estimated Library Cache Factr: Factor
-
Note there is often a 1:Many correlation between a single logical object in the Library Cache, and the physical number of memory objects associated with it. Therefore comparing the number of Lib Cache objects (e.g. in v$librarycache), with the number of Lib Cache Memory Objects is invalid.
Shared Pool Size(M) |
SP Size Factr |
Est LC Size (M) |
Est LC Mem Obj |
Est LC Time Saved (s) |
Est LC Time Saved Factr |
Est LC Load Time (s) |
Est LC Load Time Factr |
Est LC Mem Obj Hits |
352 |
0.38 |
115 |
15,602 |
547,132 |
0.88 |
82,833 |
7.60 |
13,561,473 |
448 |
0.48 |
210 |
20,206 |
559,218 |
0.90 |
70,747 |
6.49 |
13,681,539 |
544 |
0.59 |
304 |
25,430 |
564,732 |
0.91 |
65,233 |
5.99 |
13,732,206 |
640 |
0.69 |
397 |
29,804 |
585,824 |
0.95 |
44,141 |
4.05 |
13,761,147 |
736 |
0.79 |
492 |
31,706 |
606,741 |
0.98 |
23,224 |
2.13 |
13,779,369 |
832 |
0.90 |
587 |
33,581 |
614,849 |
0.99 |
15,116 |
1.39 |
13,791,238 |
928 |
1.00 |
682 |
35,624 |
619,069 |
1.00 |
10,896 |
1.00 |
13,795,452 |
1,024 |
1.10 |
777 |
37,928 |
621,113 |
1.00 |
8,852 |
0.81 |
13,798,083 |
1,120 |
1.21 |
872 |
40,162 |
623,021 |
1.01 |
6,944 |
0.64 |
13,799,705 |
1,216 |
1.31 |
967 |
42,895 |
624,574 |
1.01 |
5,391 |
0.49 |
13,800,847 |
1,312 |
1.41 |
1,062 |
45,835 |
626,304 |
1.01 |
3,661 |
0.34 |
13,801,787 |
1,408 |
1.52 |
1,157 |
48,677 |
627,737 |
1.01 |
2,228 |
0.20 |
13,802,717 |
1,504 |
1.62 |
1,252 |
52,032 |
636,469 |
1.03 |
1 |
0.00 |
13,803,727 |
1,600 |
1.72 |
1,347 |
56,719 |
637,734 |
1.03 |
1 |
0.00 |
13,804,715 |
1,696 |
1.83 |
1,442 |
60,885 |
638,457 |
1.03 |
1 |
0.00 |
13,805,622 |
1,792 |
1.93 |
1,537 |
63,993 |
638,640 |
1.03 |
1 |
0.00 |
13,806,647 |
1,888 |
2.03 |
1,632 |
66,977 |
638,660 |
1.03 |
1 |
0.00 |
13,807,680 |
Library Cache Activity
-
"Pct Misses" should be very low
Namespace |
Get Requests |
Pct Miss |
Pin Requests |
Pct Miss |
Reloads |
Invali- dations |
BODY |
5,545 |
0.20 |
7,806 |
0.40 |
20 |
0 |
CLUSTER |
91 |
4.40 |
155 |
3.23 |
1 |
0 |
INDEX |
75 |
25.33 |
140 |
34.29 |
29 |
0 |
SQL AREA |
660,357 |
26.67 |
3,184,169 |
9.38 |
8,452 |
120 |
TABLE/PROCEDURE |
20,169 |
2.45 |
965,511 |
0.30 |
1,268 |
0 |
TRIGGER |
202 |
0.00 |
1,472 |
0.20 |
3 |
0 |
我是怎麽判斷shared pool過小的呢?AWR裏面提供了多個指標,這裏硬解析不是太高,每秒3個,說明硬解析不會導致該問題,shared pool advice已經說得很明白了,當前shared pool只有928m,Oracle建議把shared pool至少調整到1504m。同時查看Library cache activtiy,大家註意觀察pct miss,SQL AREA的pct miss居然達到26.67%,而且重載了8452次,那麽我完全可以肯定就是由於shared pool太小,導致SQL被大量重載,從而引發library cache latch競爭。
Library cache latch競爭還有可能是具有高version_count的SQL導致的,某個session去執行一個具有很高version_count的SQL需要pin住child cursor,而由於child cursor過多,在未pin住child cursor之前不會釋放library cache latch,這樣當其他session想運行該SQL的時候就會發生library cache latch爭用,那麽遇到這種情況請檢查cursor_sharing參數的設置,另外請查詢是否遇到bug,或者由於系統中不同schema出現大量同名的表名,這樣請更改設計。
在第二個案例中,由於shared pool設置過小還導致了shared pool latch處於top wait event 中的第二名。Shared pool latch是用來幹嘛的呢?Shared pool latch用來保護共享池的結構,在分配,釋放共享池空間的時候就會獲得該latch,那麽在這個案例中,由於共享池太小,在對一個新的SQL進行硬解析的時候需要老化某些對象,為新對象騰出空間,那麽這個釋放空間的過程就需要獲得shared pool latch。當然了,在進行硬解析,也需要獲得一個shared pool latch因為硬解析需要申請分配shared pool空間,而分配空間的時候就需要獲得該latch
Oracle Shared Pool 原理