【分享】latch free等待事件(一)
論壇的兄弟太好了,這幾個文件非常好,感謝!
Latch free等待事件
原文:oracle wait interface—a practical guide to performance diagnostics & tuning
Richmond shee
Kirtikumar deshpande
K gopalakrishnan
Mcgraw-hill/osborne
2100 powell street, 10th floor
Emeryville, california 94608
U.s.a.
Chapter 6: interpreting locks-related wait events - latch free
文件修訂歷史:
版本 |
時間 |
作者 |
1.00 |
2006-4-21 |
NinGoo |
|
|
|
本文只是對原文的一個大概的翻譯,建議最好還是閱讀原文。
如果你發現有任何問題,歡迎反饋NinGoo@itpub.net
Latch free等待事件的三個引數:p1-latch的地址;p2-latch編號;p3-請求次數。從oracle10g起,latch free不再包含所有的latch等待,有些latch等待可能表現為單獨的等待事件,這個後面有提到一些這樣的等待事件,一般情況下我們還是統稱為latch free等待事件。在處理latch free等待事件時,需要注意以下幾點:
n Latch只是用來保護sga中的記憶體結構。對資料庫中的物件的保護,使用的lock而不是latch。Oracle sga中有許多latch,用來保護sga中各種記憶體結構不會因為併發訪問而損壞。
n 等待latch的是oracle會話。不同的latch型別會導致會話採取不同的策略。
n 在oracle9i(包括9i)之前,latch free等待事件包括了所有的latch等待,但從oracle10g起,latch被分成不同的種類,並且某些latch表現為獨立的等待事件。
什麼是latch
Latch是一種鎖機制。你應該已經熟悉latch的概念和用法,雖然可能你自己並沒有意識到。在日常的工作和交流中,latch都經常出現,比如你鎖門時,需要獲得一個latch;或者你坐到車裡,繫上安全帶,你就把自己放在一個latch的保護中了。
在oracle中,latch是一種輕量級的鎖。一般來說,latch由三種記憶體元素組成:pid(程式id),記憶體地址和記憶體長度。Latch保證對共享資料結構的排它性訪問,以此來保證記憶體結構的完整性不受到損壞。在多個會話同時修改或者檢視(inspect)sga中同一個記憶體結構時,必須序列化訪問以保證sga中資料結構的完整性。
Latch和lock的異同
Latch和lock有許多不同之處。下表列出了latch和lock之間的比較結果。
|
Latch |
Lock |
目的 |
只有一個目的:保證對記憶體結構的排他性訪問(從oracle9i開始,cache buffers chain latch可以允許只讀共享訪問) |
兩個目的:如果鎖模式是相容的,允許多個程式共享相同的資源;如果鎖模型是不相容的,保證對共享資源的排它性訪問。 |
適用場景 |
只能應用於sga中的資料結構,保護記憶體物件。Latch隻影響單次操作,而和事務無關。 |
保護資料庫物件,諸如表,資料塊和狀態物件等。由應用程式驅動,控制對資料庫中資料和後設資料的訪問。 Lock是事務性的。 |
獲取方式 |
兩種模式:willing-to-wait和no-wait |
六種模式:null, row share, row exclusive, share, share row exclusive和exclusive |
範圍 |
資訊都儲存在記憶體中,並且只在本例項可見――latch是例項級別的 |
資訊儲存在資料庫中,並且該資料庫的所有例項都可見――lock是資料庫級的 |
複雜度 |
使用簡單機器指令比如:test-and-set, compare-and-swap或其他簡單的cpu指令實現。由於cpu指令平臺相關,所以latch在不同的平臺的具體實現不一樣。 輕量級的。 |
需要上下文切換(context siwtch),使用一系列指令實現。 重量級的。 |
持續事件 |
非常短暫(通常是微妙級的) |
通常在整個事務中都持有。 |
排隊機制 |
當一個程式獲取latch失敗,轉入睡眠狀態時,他的請求不需要按順序排隊(一個例外情況:latch wait list latch需要排隊)。 |
當一個程式獲取lock失敗,它的請求會進入一個佇列,除非指定nowait。 |
死鎖 |
Latch的實現方式不會產生死鎖(不排隊) |
Lock的排隊機制可能導致死鎖。死鎖發生時會產生相應的跟蹤檔案。 |
Latch家族
Latch有三種:父latch,子latch和獨立latch。父latch和獨立latch在oracle的核心程式碼中固化,子latch則在例項啟動時創造。V$latch_parent和v$latch_children檢視分別包含父latch和子latch的統計資訊。而v$latch則包含獨立latch,父latch及其相應子latch的聚合統計資訊。
Latch的獲取
程式獲取latch有兩種模式:willing-to-wait和no_wait。No-wait模式只在少數latch中使用。通過no-wait模式獲取latch的統計資訊記錄在immediate_gets和immediate_misses列中,這些列在v$latch,v$latch_parent,v$latch_children檢視中都存在。一般來說,no-wait模式在第一次獲取一些有很多子latch的latch比如redo copy時使用。如果一個程式第一次獲取這些子latch中的任何一個失敗,它會立即使用no-wait模式詢問下一個。只有當採用no-wait模式試圖獲取所有的子latch都失敗以後,才會轉而採用willing-to-wait模式。
通過willing-to-wait模式獲取latch的統計資訊存放在gets和misses列中。每當一個程式用willing-to-wait模式去獲取一個latch時,gets都會增加。
如果程式在第一次請求latch時,latch可用,就會直接獲得該latch。在修改任何受到保護的資料結構之前,程式會將一些恢復資訊寫入到latch恢復區,這樣當獲得latch的程式發生異常時,pmon程式才能夠清理該程式持有的latch。
如果請求latch時,該latch不可用,程式就會在cpu中等待一小段時間(spin)然後重新請求latch。如果latch一直不可用,該過程(spin一段時間然後重新請求)會一直重複。重複的次數由隱含引數_spin_count決定,預設值2000。如果在請求_spin_count次之內獲得了latch,就對spin_gets和misses列各加一,否則,程式在v$session_wait中記錄latch free等待事件,然後釋放cpu,轉入睡眠狀態。睡眠一定時間後,程式被喚醒並重覆上面的過程,一直到獲得latch。在成功獲得latch後,才會更行sleep列得統計資訊。
由於程式只有在獲得latch後才會停止對latch得請求,如果某個持有latch的程式發生異常,其他請求該latch的程式該怎麼辦?豈不是要一直等待下去?不會的。當一個程式請求latch失敗一定次數後,它會請求pmon程式檢視該latch的持有者,如果持有程式異常,pmon就會清理該程式,釋放latch。
每個latch都有一個從0到13的優先順序編號。父latch和獨立latch的優先順序編號是在oracle核心程式碼中固定的。子latch是÷在例項啟動時建立,其優先順序編號從其父latch繼承。使用優先順序可以避免死鎖。
n 當一個程式請求no-wait模式的latch時,該latch的優先順序編號必須和它當前已經持有的latch的優先順序編號相同。
n 當一個程式請求willing-to-wait模式的latch時,該latch的優先順序編號必須比它當前已經持有的latch的優先順序編號要大。
短等待latch與長等待latch
大多數latch都是短等待latch,所以,程式請求latch時不會等待太長的時間。Oracle程式請求latch失敗而導致進入睡眠狀態,每次睡眠時間按雙指數佇列增長,比如睡眠時間可能像下面的佇列一樣:1,1,2,2,4,4,8,8,16,16,32,32,64,64(釐秒)……,最長的睡眠時間由隱含引數_max_ exponential_sleep,預設2秒。但是如果一個程式當前已經持有其他的latch,則最長睡眠時間會減少為_max_sleep_holding_latch,預設值4釐秒。這樣,如果一個程式已經持有latch,就不允許睡眠太長的時間,否則可能會使其他等待該程式所持有的latch的程式的等待時間過長。
有小部分latch屬於長等待latch,這意味著這些latch被可能長久持有。如果請求該latch的程式進入睡眠狀態,需要其他程式來喚醒,這會產生一個latch wait posting等待事件,該行為由隱含引數_latch_wait_posting控制。在oracle8i,只有2個長等待latch,如下面的示例sql(oracle9i和oracle10g有更多長等待latch)所示。_latch_wait_posting引數從oracle9i起已經廢棄,使用latch wait posting的latch的統計資訊被記錄在waiters_woken列中。
Select name, immediate_gets, immediate_misses,
gets, misses, sleeps, waiters_woken
From v$latch
Where waiters_woken > 0;
immediate immediate waiters
Name gets misses gets misses sleeps woken
------------------------ --------------- -------------------- ----------------- ------------- --------------- ---------------
Shared pool 0 0 18464156 3124 1032 485
Library cache 85508 124 1564400540 4334362 1516400 690419
Latch分類
從oracle9iR2開始,latch可以被分成不同的型別,每一類latch都可以有不同的_spin_count值。在早期版本中,如果改變_spin_count值,會對系統中所有的latch造成影響。這樣可能會增加cpu的負擔,而latch分類則正是為解決這個問題而引入的。例如,如果cache buffers chains latch的sleep次數很多,而且cpu資源充足,我們就可以將cache buffer chains latch所在的分類的_spin_count的值調高。高_spin_count值可以降低sleeps和misses的次數,代價是花費更多cpu時間。內部檢視x$ksllclass (kernel serverice lock latches class)包含了latch的所有八種型別的資訊。其中indx列就是latch型別編號。
Select indx, spin, yield, waittime
from x$ksllclass;
indx spin yield waittime
---------- ---------- ---------- ----------
0 20000 0 1
1 20000 0 1
2 20000 0 1
3 20000 0 1
4 20000 0 1
5 20000 0 1
6 20000 0 1
7 20000 0 1
8 rows selected.
x$ksllclass中的每行記錄都和一個隱藏引數_latch_class_n關聯,通過這些隱含引數,你可以改變相應的_spin_count,yield和waittime的值(x$檢視不能由使用者手動更新)。例如,latch型別0由引數_latch_class_0控制,latch型別1由引數_latch_class_1控制。如果你想將cache buffers chains latch的_spin_count值改成10,000,首先你需要知道latch的編號,通過以下查詢可以獲得
Select latch#, name
From v$latchname
Where name = ’cache buffers chains’;
latch# name
---------- -------------------------------
97 cache buffers chains
然後,你需要修改init.ora中的下面2個引數:
_latch_class_1 = "10000"
_latch_classes = "97:1"
第一個引數_latch_class_1將型別1的spin_count值改為10,000;
第二個引數_latch_classes 將編號為97的latch分配到型別1。
再次查詢x$ksllclass,我們可以發現:
Select indx, spin, yield, waittime
From x$ksllclass;
indx spin yield waittime
---------- ---------- ---------- ----------
0 20000 0 1
1 10000 0 1
2 20000 0 1
3 20000 0 1
4 20000 0 1
5 20000 0 1
6 20000 0 1
7 20000 0 1
8 rows selected.
Select a.kslldnam, b.kslltnum, b.class_ksllt
From x$kslld a, x$ksllt b
Where a.kslldadr = b.addr
And b.class_ksllt > 0;
Kslldnam kslltnum class_ksllt
------------------------- ---------- -----------
Process allocation 3 2
Cache buffers chains 97 1
注意:如果伺服器的cpu資源緊張,請不要增加_spin_count的值。當然,預設值2000是很久以前定下來的值,當時的cpu比現在的cpu要慢得多。
Latch free等待事件可以告訴我們什麼?
如果我們在v$session_wait中發現有latch free等待事件,就意味著,程式在請求一個willing_to_wait模式的latch,在重試了_spin_count次後還是沒有獲得latch,然後轉入睡眠狀態了。如果latch爭用嚴重,將會由於不斷的spin導致cpu資源緊張,從而增加系統響應時間。
V$system_event檢視的total_waits列記錄了程式獲取willing-to-wait模式latch失敗的次數。V$latch的sleeps列記錄了程式由於等待某個latch而進入睡眠狀態的次數。由於一個程式在_spin_count次嘗試請求latch失敗後會轉入睡眠狀態,total_waits列應該等於sleeps列的值的和,如以下sql所示。但是,某些時候,total_waits會比sleeps的和要大,這是因為,只有在程式獲得latch後才會更新total_waits的值,而不是每次請求latch失敗就更新。
Select a.total_waits, b.sum_of_sleeps
from (select total_waits from v$system_event where event = ’latch free’) a,
(select sum(sleeps) sum_of_sleeps from v$latch) b;
total_waits sum_of_sleeps
----------- -------------
414031680 414031680
由於latch free等待時間一般較短,所以在很少一段時間內,total_waits就可能變得非常大,這並不一定意味著系統有問題。只有當time_waited的值也非常顯著的時候,你才需要關注latch free等待事件。
Latch失敗區域(latch miss locations)
V$latch_misses檢視儲存了latch失敗在oracle核心程式碼中的區域資訊。這些資訊對於oracle support診斷latch等待事件有幫助。你可以通過以下查詢檢視位置資訊。Steve adams有篇非常棒的關於這方面的文章http://www.ixora.com.au/newsletter/2001_02.htm
Select location,
parent_name,
wtr_slp_count,
sleep_count,
longhold_count
from v$latch_misses
where sleep_count > 0
order by wtr_slp_count, location;
longhold
location parent_name wtr_slp_count sleep_count count
-------------------- -------------------- ------------- ----------- --------
. . .
Kglupc: child library cache 7879693 11869691 0
kghupr1 shared pool 8062331 5493370 0
kcbrls: kslbegin cache buffers chains 9776543 14043355 0
kqrpfl: not dirty row cache objects 15606317 14999100 0
kqrpre: find obj row cache objects 20359370 20969580 0
kglhdgn: child: library cache 23782557 9952093 0
kcbgtcr: fast path cache buffers chains 26729974 23166337 0
kglpnc: child library cache 27385354 7707204 0
Oracle10gR1中的latch
在Oracle10g之前,所有的latch等待都顯示為latch free等待事件。你可以通過latch free事件的p2引數和v$latch.latch#關聯或者通過10046事件來查詢某個程式爭用的是哪個latch。而在Oracle10g中,latch被分成許多獨立的等待。下面是oracle10gR1的latch一個列表:
Select name
from v$event_name
where name like ’latch%’
order by 1;
name
----------------------------------------------------------------
latch activity
latch free
latch: in memory undo latch
latch: kcl gc element parent latch
latch: mql tracking latch
latch: cache buffer handles
latch: cache buffers chains
latch: cache buffers lru chain
latch: checkpoint queue latch
latch: enqueue hash chains
latch: gcs resource hash
latch: ges resource hash list
latch: latch wait list
latch: library cache
latch: library cache lock
latch: library cache pin
latch: messages
latch: object queue header heap
latch: object queue header operation
latch: parallel query alloc buffer
latch: redo allocation
latch: redo copy
latch: redo writing
latch: row cache objects
latch: session allocation
latch: shared pool
latch: undo global data
latch: virtual circuit queues
28 rows selected.
Latch產生的原因,診斷以及對策
Latch爭用通常意味這某個程式持有latch的時間過長。如果latch爭用明顯,系統效能將顯著下降。在高併發的環境中,latch爭用經常發生,並且你無法完全消除latch爭用。在v$system_event中總會出現latch free等待事件。只有當time_waited相對例項啟動以來的總時間比較明顯時,你才需要關注latch爭用。當latch在系統範圍內的等待時間比較顯著時,你可以通過v$latch中的sleeps列來發現爭用顯著的latch:
Select name, gets, misses, immediate_gets, immediate_misses, sleeps
from v$latch
order by sleeps;
immediate immediate
name gets misses gets misses sleeps
-------------------- ---------- ---------- ----------- --------- ----------
enqueue hash chains 42770950 4279 0 0 1964
shared pool 9106650 5400 0 0 2632
row cache objects 69059887 27938 409 0 7517
enqueues 80443314 330167 0 0 13761
library cache 69447172 103349 465827 190 44328
cache buffers chains 1691040252 1166249 61532689 5909 127478
. . .
對不同的latch,其產生的原因以及可採取的對策都有所不同。詳細的說明所有的latch可以寫成一本書了。這裡我們只選擇最常見的五個latch加以說明:shared pool, library cache, cache buffers chains, cache buffers lru chain和row cache objects。
Shared pool和library cache latch
Oracle的共享池由不同的結構組成。主要包括:資料字典快取,sql區和庫快取。通過v$sgastat你可以檢視其他一些結構。Shared pool latch主要用來保護共享池的記憶體結構,當分配或者釋放共享池記憶體時需要先獲得該latch。例如,為一個新的sql語句或pl/sql過程、函式、包,觸發器等分配空間(硬解析)時,或者為換出、清除某些記憶體塊,以便為新的物件騰出足夠的空間時,都需要獲取shared pool latch。
在oracle9i之前,共享池記憶體結構由一個獨立shared pool latch保護,從9i開始,則有最多7個子latch可以用於共享池的保護。這也是為什麼oracle9i可以將共享池分成多個子共享池的原因(伺服器至少需要4顆cpu,並且shared_pool_size大於250m才能使用多個子共享池的特性)。子共享池的個數可以通過隱含引數_kghdsidx_count手動調節,該引數同時會指定合適的shared pool子latch的個數。如果你手動增加子共享池的個數,你應該同時增加shared_pool_size的值,因為每個子共享池都有自己的結構,lru列表和shared pool latch。否則,例項啟動時可能會遇到以下錯誤:
Ora-04031: unable to allocate 32 bytes of shared memory ("shared pool","unknown object","sga heap(5,0)","fixed allocation callback").
下面的統計資訊是從一個16顆cpu,shared_pool_size為256m的oracle9i資料庫中讀取的。由_kghdsidx_count引數可知共享池被分成2個子池,通過x$kghlu(kernel generic heap lru)可以知道lru列表也有2個。v$latch_children檢視顯示了7個子latch中的2個已經被使用。
Select a.ksppinm, b.ksppstvl
from x$ksppi a, x$ksppsv b
where a.indx = b.indx
and a.ksppinm = ’_kghdsidx_count’;
ksppinm ksppstvl
------------------ ----------
_kghdsidx_count 2
select addr, kghluidx, kghlufsh, kghluops, kghlurcr, kghlutrn, kghlumxa
from x$kghlu;
addr kghluidx kghlufsh kghluops kghlurcr kghlutrn kghlumxa
---------------- -------- ---------- ---------- -------- -------- ----------
80000001001581b8 2 41588416 496096025 14820 17463 2147483647
8000000100157e18 1 46837096 3690967191 11661 19930 2147483647
select addr, name, gets, misses, waiters_woken
from v$latch_children
where name = ‘shared pool’;
addr name gets misses waiters_woken
---------------- ------------- ----------- ---------- -------------
c00000004c5b06b0 shared pool 0 0 0
c00000004c5b0590 shared pool 0 0 0
c00000004c5b0470 shared pool 0 0 0
c00000004c5b0350 shared pool 0 0 0
c00000004c5b0230 shared pool 0 0 0
c00000004c5b0110 shared pool 1385021389 90748637 12734879
c00000004c5afff0 shared pool 2138031345 413319249 44738488
庫快取中主要儲存遊標,sql語句,執行計劃,分析樹等。這些結構由library cache latch保護。當oracle程式修改、檢查、銷連線(pinning)、鎖定、裝載,或者執行庫快取中的結構時,都需要先獲得library cache latch。通過查詢v$latch_children可以得知當前例項中的library cache子latch的個數。通常應該為大於cpu個數的最小質數,該值由隱含引數_kgl_latch_count控制。從oracle9i開始,v$sqlarea檢視增加了一個child_latch列,用來指示遊標在各個library cache latch是如何分佈的。
Select count(*)
from v$latch_children
where name = ‘library cache’;
Shared pool 和 library cache latch爭用原因一 ―― 分析
Shared pool和library cache latch爭用通常是由於硬分析引起。硬分析需要分配新的遊標,或者將已經換出的遊標重新執行。硬分析過多說明sql語句沒有充分繫結變數。硬分析是代價十分昂貴的操作,在分析期間需要一直持有ibrary cache latch。
n 通過下列查詢可以發現系統中是否存在大量硬分析。軟分析數則可以用總分析數減去硬分析數獲得
Select a.*, sysdate-b.startup_time days_old
from v$sysstat a, v$instance b
where a.name like ‘parse%’;
statistic# name class value days_old
---------- ------------------------- ----- ---------- ----------
230 parse time cpu 64 33371587 4.6433912
231 parse time elapsed 64 63185919 4.6433912
232 parse count (total) 64 2137380227 4.6433912
233 parse count (hard) 64 27006791 4.6433912
234 parse count (failures) 64 58945 4.6433912
備註:分析失敗可能是由於“ora-00942: table or view does not exist”錯誤或者共享記憶體不足。
n 檢視當前會話是否有大量硬分析
Select a.sid, c.username, b.name, a.value,
round((sysdate - c.logon_time)*24) hours_connected
from v$sesstat a, v$statname b, v$session c
where c.sid = a.sid
and a.statistic# = b.statistic#
and a.value > 0
and b.name = ‘parse count (hard)’
order by a.value;
sid username name value hours_connected
---- ---------- ------------------ ---------- ---------------
510 sys parse count (hard) 12 4
413 pmappc parse count (hard) 317 51
37 pmhcmc parse count (hard) 27680 111
257 pmappc parse count (hard) 64652 13
432 pmappc parse count (hard) 105505 13
在oracle10g中,通過v$sess_time_model檢視中對硬分析和失敗分析的時間統計資訊,可以知道硬分析的來源。下面的例子顯示了某個會話的v$sess_time_model資訊。
Select *
From v$sess_time_model
Where sid = (select max(sid) from v$mystat);
sid stat_id stat_name value
---- ---------- ------------------------------------------------ ----------
148 3649082374 db time 11141191
148 2748282437 db cpu 9530592
148 4157170894 background elapsed time 0
148 2451517896 background cpu time 0
148 4127043053 sequence load elapsed time 0
148 1431595225 parse time elapsed 3868898
148 372226525 hard parse elapsed time 3484672
148 2821698184 sql execute elapsed time 9455020
148 1990024365 connection management call elapsed time 6726
148 1824284809 failed parse elapsed time 0
148 4125607023 failed parse (out of shared memory) elapsed time 0
148 3138706091 hard parse (sharing criteria) elapsed time 11552
148 268357648 hard parse (bind mismatch) elapsed time 4440
148 2643905994 pl/sql execution elapsed time 70350
148 290749718 inbound pl/sql rpc elapsed time 0
148 1311180441 pl/sql compilation elapsed time 268477
148 751169994 java execution elapsed time 0
上面的分析統計資訊可以按照下面的方法分組:
1. parse time elapsed
2. hard parse elapsed time
3. hard parse (sharing criteria) elapsed time
4. hard parse (bind mismatch) elapsed time
2. failed parse elapsed time
3. failed parse (out of shared memory) elapsed time
n 確定系統中的常量sql語句(literal sql),它們往往都是可以使用並且應該使用繫結變數的。下面通過查詢v$sqlarea檢視,列出超過4個執行例項的sql語句的前40個字元,這裡假設你的系統中前40個字元相同的語句被認為是沒有使用繫結變數的常量sql。很明顯,如果使用更長的字串或者更多的執行例項作為過濾條件,得到的結果sql語句會少很多。然後你可以根據得到的結果,建議程式開發人員對這些常量sql語句儘量使用繫結變數。
Select hash_value, substr(sql_text,1,80)
from v$sqlarea
where substr(sql_text,1,40) in (select substr(sql_text,1,40)
from v$sqlarea
having count(*) > 4
group by substr(sql_text,1,40))
order by sql_text;
hash_value substr(sql_text,1,80)
---------- -----------------------------------------------------------------
2915282817 select revenue.customer_id, revenue.orig_sys, revenue.service_typ
2923401936 select revenue.customer_id, revenue.orig_sys, revenue.service_typ
303952184 select revenue.customer_id, revenue.orig_sys, revenue.service_typ
416786153 select revenue.customer_id, revenue.orig_sys, revenue.service_typ
2112631233 select revenue.customer_id, revenue.orig_sys, revenue.service_typ
3373328808 select region_id from person_to_chair where chair_id = 988947
407884945 select region_id from person_to_chair where chair_id = 990165
3022536167 select region_id from person_to_chair where chair_id = 990166
3204873278 select region_id from person_to_chair where chair_id = 990167
643778054 select region_id from person_to_chair where chair_id = 990168
2601269433 select region_id from person_to_chair where chair_id = 990169
3453662597 select region_id from person_to_chair where chair_id = 991393
3621328440 update plan_storage set last_month_plan_id = 780093, pay_code
2852661466 update plan_storage set last_month_plan_id = 780093, pay_code
380292598 update plan_storage set last_month_plan_id = 780093, pay_code
2202959352 update plan_storage set last_month_plan_id = 780093, pay_code
. . .
在oracle9i中,也可以通過如下的語句查詢v$sql檢視中使用了相同的執行計劃的sql語句,這些語句也可能是常量sql語句。
Select plan_hash_value, hash_value
from v$sql
order by 1,2;
如果你的系統中存在大量的常量sql語句,當你將它們改為充分使用繫結變數後,對shared pool latch和library cache latch的爭用將會顯著減少。更改sql語句,使用繫結變數,這通常需要修改應用程式。另外一個不需要改動應用的方法是,修改初始化引數cursor_sharing,將其值改為force(注:原文如此。一般情況下請儘量使用similar而不是force),這個引數允許系統對一些只有常量值不一樣的sql語句共享遊標,以減少latch爭用、記憶體佔用和硬分析。
注意:在oracle8i早期版本中,使用cursor_sharing可能導致bug。在使用了物化檢視的環境中,請慎用該引數,否則可能導致長久的library cache pin等待。另外,使用cursor_sharing = force可能導致優化器生成錯誤的執行計劃。這或多或少的會對系統效能造成影響。從oracle9i起,優化器可以通過窺視pga中的資訊來進行變數繫結,以此生成合適的執行計劃,該特性可以通過隱含引數_optim_peek_user_binds來開啟,並且該特性只對那些需要硬分析的sql語句有效,這意味著會基於繫結變數的第一個值來生成執行計劃。
當一個新的sql語句到達時,oracle首先在庫快取中檢查是否已經有相同的語句存在。如果已經存在,則可以花費較小的代價執行該語句,這就是所謂的軟分析。硬分析通常意味著較壞的效能,而軟分析過多也不是什麼好事。在軟分析期間,需要持有library cache latch,並且oracle依然需要對語句進行語法和語義檢查,除非該語句已經在會話的遊標快取中。你可以通過設定引數session_cached_cursors來減少library cache latch的持有時間(具體資訊請檢視oracle metalin,編號#30804.1和 #62143.1)。但是,減少軟分析的最佳方法還是優化應用程式。最好是分析一次,執行多次(很像java的宣傳口號),而不要分析一次,執行一次。你可以通過v$sqlarea的parse_calls列來查詢分析過多的sql語句。
Shared pool latch爭用原因二 ―― 過大的共享池
從oracle9i起,由於引入了多個子共享池的特性,過大的共享池不再是一種壞事。在9i之前,過大的共享池通常會引起shared pool latch爭用。共享池中可用記憶體分成不同的記憶體塊(chunk),不同大小範圍的塊由不同的可用列表(freelist)來管理。在共享池中分配空間時,需要掃描可用列表,掃描期間,需要持有shared pool latch。過大的共享池會使得可用列表過長,從而使得shared pool latch的持有時間變長。在高併發環境中,latch持有時間過長就可能造成latch爭用(表現為較高的sleeps和misses值),尤其是大量使用常量sql的系統,對這樣的系統,不要一味想著加大共享池,更重要的是想一想你為什麼會需要儲存這麼多不能共享的語句到共享池中。
通過alter session set events ’immediate trace name heapdump level 2’可以轉存共享池資訊,從中可以看到共享池的可用列表資訊。在生成的跟蹤檔案中查詢bucket,你可以發現記憶體塊(chunk)分配到不同的bucket上。另外,你也可以通過下面的方法生成一個查詢來列出共享池的可用記憶體管理資訊。該查詢只要生成一次,就可以在生成該跟蹤檔案的資料庫中重複使用,但不要在其他不同版本的資料庫中使用,否則可能得到錯誤的結果。該查詢在oracle10gR1中不可用,因為它限制了case分支數不能超過128(具體資訊參考oracle metalink 編號#131557.1和bug號#3503496),或者你可以通過使用decode和sign函式來完成該功能。
Sql> oradebug setmypid
statement processed.
Sql> oradebug dump heapdump 2
statement processed.
Sql> oradebug tracefile_name
/u01/admin/webmon/udump/orcl_ora_17550.trc
sql> exit
(注:上面是使用oradebug獲得轉存檔案,也可以使用alter session set events ’immediate trace name heapdump level 2’)
$ grep bucket /u01/admin/webmon/udump/orcl_ora_17550.trc > tmp.lst
$ sed ’s/size=/ksmchsiz>=/’ tmp.lst > tmp2.lst
$ sed ’s/ bucket //’ tmp2.lst | sort –nr > tmp.lst
# 通過shell指令碼生成查詢
echo ’select ksmchidx, (case’
cat tmp.lst | while read line
do
echo $line | awk ’{print "when " $2 " then " $1}’
done
echo ’end) bucket#,’
echo ’ count(*) free_chunks,’
echo ’ sum(ksmchsiz) free_space,’
echo ’ trunc(avg(ksmchsiz)) avg_chunk_size’
echo ’from x$ksmsp’
echo "where ksmchcls = ’free’"
echo ’group by ksmchidx, (case’;
cat tmp.lst | while read line
do
echo $line | awk ’{print "when " $2 " then " $1’}
done
echo ’end);’
如果你發現資料庫的共享池可用列表過長,並且系統中使用了常量sql,你或許應該考慮減少shared_pool_size。這會降低系統中對shared pool latch的爭用。但要注意共享池不能太小,否則可能導致ora-04031錯誤。另外,通過使用dbms_shared_pool.keep將常用物件釘在記憶體中也是個好主意,v$db_object_cache中儲存了釘在記憶體中的物件的資訊。
Library cache latch爭用原因三 ―― 語句版本數過多
對於字元完全一致但是由於引用不同的物件而不能共享的sql語句,oracle使用多個子遊標來指向該語句的不同版本。例如,系統中有三個名叫customer的表,但是屬於不同的模式。則對於語句select * from customer,不同的模式執行該語句,語句字元上完全一樣,其hash值完全一樣,但是該語句無法共享,因為它引用的物件不同。所以會生成該語句的不同子版本。當一個sql語句有多個子版本時,oracle需要比較該語句的所有存在的子版本,在此期間需要持有library cache latch,這樣可能導致library cache latch爭用。解決這種情況也很簡單,在系統中,儘量不要使用相同的物件名。下面的查詢列出了v$sqlarea中子版本超過20的所有sql語句:
Select version_count, sql_text
from v$sqlarea
where version_count > 20
order by version_count, hash_value;
注意:在oracle8i中,語句的版本過多,可能導致和sql執行監控相關的bug(參考oracle metalink 編號#62143.1)。這個bug會導致sql無法共享。可以通過將隱含引數_sqlexec_progression_cost設定為0來禁用sql執行監控特性,該引數同時會禁止v$session_longops中的資料。
Oracle提供了檢視v$sql_shared_cursor,其中可以看到為什麼無法共享一個已經存在子游標。每個列都限制了遊標無法共享的一個原因。
-- 大寫的列是oracle9i起才有列.
-- oracle 10g R1還有其他8個列
select a.*, b.hash_value, b.sql_text
from v$sql_shared_cursor a, v$sqltext b, x$kglcursor c
where a.unbound_cursor || a.sql_type_mismatch ||
a.optimizer_mismatch || a.outline_mismatch ||
a.stats_row_mismatch || a.literal_mismatch ||
a.sec_depth_mismatch || a.explain_plan_cursor ||
a.buffered_dml_mismatch || a.pdml_env_mismatch ||
a.inst_drtld_mismatch || a.slave_qc_mismatch ||
a.typecheck_mismatch || a.auth_check_mismatch ||
a.bind_mismatch || a.describe_mismatch ||
a.language_mismatch || a.translation_mismatch ||
a.row_level_sec_mismatch || a.insuff_privs ||
a.insuff_privs_rem || a.remote_trans_mismatch ||
a.logminer_session_mismatch || a.incomp_ltrl_mismatch ||
a.overlap_time_mismatch || a.sql_redirect_mismatch ||
a.mv_query_gen_mismatch || a.user_bind_peek_mismatch ||
a.typchk_dep_mismatch || a.no_trigger_mismatch ||
a.flashback_cursor <> ’nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn’
and a.address = c.kglhdadr
and b.hash_value = c.kglnahsh
order by b.hash_value, b.piece;
Cache buffers chains latch
當一個資料塊讀入到sga中時,該塊的緩衝區頭(buffer header)會放置在一個hash bucket的連結串列(hash chain)中。該記憶體結構由一系列cache buffers chains子latch保護(又名hash latch或者cbc latch)。下圖描述了hash latch,hash bucket,buffer header和hash chain的關係
圖一. Oracle8i以上的資料緩衝區示意圖
一個程式要新增,刪除,查詢,檢視,讀取或者修改hash chain上的塊,必須先獲得cache buffers chains latch,以保證對該chain的排他訪問,為保證完整性,必須犧牲併發性。
注:從oracle9i開始,對cache buffer chains latch可用只讀共享訪問,這可以減少部分爭用,但並不能完全消除爭用。
一個特定的塊頭具體分配到哪個hash bucket,是通過dba(data block address)和隱含引數_db_block_hash_buckets實現的。例如,hash bucket = mod(dba, _db_block_hash_buckets)。通過查詢v$bh和x$bh檢視可以發現緩衝區頭的爭用,也可以通過以下語句轉存緩衝區頭的資訊:
Alter system set events ’immediate trace name buffers level 1’;
在oracle8.0之前,每一個hash bucket都有一個cache buffers chains latch(hash latch),並且hash bucket都只有一個hash chain連結串列。換句話說,hash latch,hash backet和hash chain之間是1:1:1的關係。預設的hash bucket個數為大於db_block_buffers / 4的最小質數,通過隱含引數_db_block_hash_buckets可以修改該值。例如,假如db_block_buffers = 50000,則該例項中有12501個hash latch,有12501個hash bucket,有12501個hash chain。
從oracle8i開始,oracle將hash latch和hash bucket之前的關係改成了 1:m,但hash bucket和hash chain之間還是1:1,也就是一個hash latch可以同時保護多個hash chain連結串列。這樣,可以顯著的減少系統中hash latch的個數。Hash latch的預設個數還是和db_block_buffers的值相關。當資料緩衝區小於1G時,一般都是1024個。通過隱含引數_db_blocks_hash_latches可以修改該值。下面的語句查詢例項中的hash latch數目:
Select count(distinct(hladdr))
from x$bh;
Count(distinct(hladdr))
-----------------------
1024
Select count(*)
from v$latch_children
where name = ’cache buffers chains’;
count(*)
----------
1024
Hash bucket的預設個數等於2 * db_block_buffers,可以通過隱含引數_db_block_hash_buckets修改。這樣,假如db_block_buffers=50000,則系統中有100000個hash bucket和100000個hash chain,但是隻有1024個hash latch(假設塊大小為8k)。由此可以看出,oracle8i和oracle8.0中,hash latch數目發生了顯著的變化。許多DBA認為,由於hash latch數目顯著減少,可能會導致latch爭用的增加。但是,oracle解釋說,通過以8為因子增加hash chain連結串列的個數,單個連結串列會比以前變得更短,這樣每次cache buffer chains latch的持有時間也變得更短,以此來補償latch個數減少帶來的latch爭用。但不要依賴這個機制,你還是會看到很多latch爭用。
Oracle10g使用了不同的演算法來決定系統中hash bucket的預設個數。一開始好像等於db_cache_size / 4。但後來的測試證明,在某些不同的db_cache_size值範圍內,例如當db_cache_size在132m和260m之間時,hash bucket的個數是一個常數。下面的表中列出了從oracle8i到oracle10g,不同的資料緩衝大小時的hash bucket的預設個數,其中資料塊大小都是8k。
Oracle 10g 作業系統solaris | |||||||
Db_cache_size |
32m |
64m |
128m |
256m |
512m |
1024m |
2048m |
_ksmg_granule_size |
4m |
4m |
4m |
4m |
4m |
16m |
16m |
_db_block_buffers |
3976 |
7952 |
15904 |
31808 |
63616 |
127232 |
254464 |
_db_block_hash_buckets |
8192 |
16384 |
32768 |
65536 |
131072 |
262144 |
524288 |
_db_block_hash_latches |
1024 |
1024 |
1024 |
1024 |
1024 |
1024 |
2048 |
Oracle9i 作業系統solaris | |||||||
Db_cache_size |
32m |
64m |
128m |
256m |
512m |
1024m |
2048m |
_ksmg_granule_size |
4m |
4m |
16m |
16m |
16m |
16m |
16m |
_db_block_buffers |
4000 |
8000 |
16016 |
32032 |
64064 |
128128 |
256256 |
_db_block_hash_buckets |
8009 |
16001 |
32051 |
64067 |
128147 |
256279 |
512521 |
_db_block_hash_latches |
1024 |
1024 |
1024 |
1024 |
1024 |
1024 |
2048 |
Oracle8i 作業系統solaris | |||||||
Db_block_buffers |
4000 |
8000 |
16016 |
32032 |
64064 |
128128 |
192192 |
_db_block_hash_buckets |
8000 |
16000 |
32032 |
64064 |
128128 |
256256 |
384384 |
_db_block_hash_latches |
1024 |
1024 |
1024 |
1024 |
1024 |
1024 |
2048 |
Cache buffers chains latch爭用原因一 ―― 低效的sql語句
低效的sql語句是導致cache buffers chains latch爭用的主要原因。在高併發系統中, atch free時間可能因此非常明顯。典型的情況是,應用程式開啟多個併發會話執行相同的低效sql,並且訪問同樣的資料集。
你應該時刻銘記下面三點:
n 每次邏輯讀都需要請求一次latch。
n 只有獲得某個latch之後才會停止對該latch的不斷請求。
n 在某個時刻,只有一個程式可以獲得cache buffers chains latch,而該latch可能用於保護很多的資料塊,其中的某些塊可能正在被其他程式請求(當然,前面也已經提過,oracle9i允許只讀性質的cache buffers chains latch共享)。
一般而言,較少的邏輯讀意味著較少的latch請求,也就意味著較少的latch爭用和更好的系統效能。所以,你應該找出導致cache buffers chains latch爭用的低效sql語句,優化這些語句,儘量降低其邏輯讀。那些buffers_get/executions比值較大的sql可能就是你需要調整的語句。
注1:某些dba可能通過修改隱含引數_db_blocks_hash_latches來增加系統中cache buffers chains latch的個數,而不是首先去優化低效的sql語句,這是不正確的,增加latch能暫時降低對latch的爭用,但這是治標不治本的方法。
注2:在sun solareis平臺上,我們將一個資料庫從oracle8.1.7.4升級到oracle9.2.05之後,發現了大量的cache buffers chains latch爭用,新的優化器為應用程式生成了低效的執行計劃。一些隱藏的優化器相關的引數,在oracle8i中是無效的,但在oracle9i中有效。在重設這些引數後,問題得意解決。如果你遭遇到同樣的情況,建議請求oracle的技術支援。
Cache buffers chains latch爭用原因二 ―― 熱點塊
熱點塊是導致cache buffers chains latch爭用的另外一個主要原因。當多個程式重複訪問一個或多個由同一個cache buffers chains latch保護的塊時會導致該問題。這通常是應用程式引起的。在這種情況下,增加cache buffers chains latch的個數對熱點塊導致的爭用沒有什麼作用。因為資料塊分佈在哪個hash bucket和hash chain上是由塊地址(dba:data block address)和hash bucket的個數決定的,和hash latch的個數沒有關係。只要塊地址和hash bucket數沒有改變,這些熱點塊還是會分佈在原來的hash bucket和hash chain上,還是由原來的hash latch保護,那麼就還會對這些hash latch產生爭用。除非系統中latch數目顯著的增加(這樣每個latch管理的hash bucket就會很少,甚至一個latch管理一個hash bucket,這樣原來的熱點塊可能就會有其他的幾個latch來管理,而不再需要爭用原來的那個latch)。
解決這樣的cache buffers chains latch爭用,最好的方法是找出熱點塊。通過latch free等待事件的p1raw引數可以知道是否是因為熱點塊導致了latch爭用。(在oracle10g中,cache buffers chains latch的相關等待事件不再是latch free,而是cache buffers chains)。P1raw引數是latch的地址。如果多個會話都在等待同一個latch地址,那麼恭喜你遇到熱點塊問題了。下面的例子中,可以發現由地址為00000400837d7800 和00000400837de400的latch保護的hash chain中存在熱點塊(多個會話都在等待這兩個地址的latch)。
Select sid, p1raw, p2, p3, seconds_in_wait, wait_time, state
from v$session_wait
where event =’latch free’
order by p2, p1raw;
sid p1raw p2 p3 seconds_in_wait wait_time state
---- ---------------- --- --- --------------- ---------- ------------------
38 00000400837d7800 98 1 1 2 waited known time
42 00000400837d7800 98 1 1 2 waited known time
44 00000400837d7800 98 3 1 4 waited known time
58 00000400837d7800 98 2 1 10 waited known time
85 00000400837d7800 98 3 1 12 waited known time
214 00000400837d7800 98 1 1 2 waited known time
186 00000400837d7800 98 3 1 14 waited known time
149 00000400837d7800 98 2 1 3 waited known time
132 00000400837d7800 98 2 1 2 waited known time
101 00000400837d7800 98 3 1 4 waited known time
222 00000400837d7800 98 3 1 12 waited known time
229 00000400837d7800 98 3 1 4 waited known time
230 00000400837d7800 98 3 1 11 waited known time
232 00000400837d7800 98 1 1 20 waited known time
257 00000400837d7800 98 3 1 16 waited known time
263 00000400837d7800 98 3 1 5 waited known time
117 00000400837d7800 98 4 1 4 waited known time
102 00000400837d7800 98 3 1 12 waited known time
47 00000400837d7800 98 3 1 11 waited known time
49 00000400837d7800 98 1 1 2 waited known time
99 00000400837d9300 98 1 1 32 waited known time
51 00000400837dd200 98 1 1 1 waited known time
43 00000400837de400 98 1 1 2 waited known time
130 00000400837de400 98 1 1 10 waited known time
89 00000400837de400 98 1 1 2 waited known time
62 00000400837de400 98 0 1 -1 waited known time
150 00000400837de400 98 1 1 9 waited known time
195 00000400837de400 98 1 1 3 waited known time
67 00000400837de400 98 1 1 2 waited known time
下一步,就是找出這些熱點塊以及造成latch爭用的sql語句。這是因為cache buffers chains latch通常保護很多個塊,這些熱點塊可能屬於這些sql中使用的某個表。從oracle8i開始,你可以通過接觸點計數(tch:touch count)來發現熱點塊。一般來說,熱點塊的tch會比較高。但是要記住,當塊從lru列表的冷端移動到熱端後,tch會被清0。所以, tch為0的塊不一定就不是熱點塊。
-- 這裡使用了前面例子中的p1raw (00000400837d7800).
Select a.hladdr, a.file#, a.dbablk, a.tch, a.obj, b.object_name
from x$bh a, dba_objects b
where (a.obj = b.object_id or a.obj = b.data_object_id)
and a.hladdr = ’00000400837d7800’
union
select hladdr, file#, dbablk, tch, obj, null
from x$bh
where obj in (select obj from x$bh where hladdr = ’00000400837d7800’
minus
select object_id from dba_objects
minus
select data_object_id from dba_objects)
and hladdr = ’00000400837d7800’
order by 4;
hladdr file# dbablk tch obj object_name
---------------- ----- ------- ---- ----------- --------------------
00000400837d7800 16 105132 0 19139 route_history
00000400837d7800 16 106156 0 19163 telco_orders
00000400837d7800 26 98877 0 23346 t1
00000400837d7800 16 61100 0 19163 telco_orders
00000400837d7800 16 26284 0 19059 fp_eq_tasks
00000400837d7800 7 144470 0 18892 report_process_queue
00000400837d7800 8 145781 0 18854 pa_equipment_union
00000400837d7800 249 244085 0 4294967295
00000400837d7800 7 31823 1 18719 candidate_events
00000400837d7800 13 100154 1 19251 event
00000400837d7800 7 25679 1 18730 candidate_zoning
00000400837d7800 7 8271 1 18719 candidate_events
00000400837d7800 7 32847 2 18719 candidate_events
00000400837d7800 8 49518 2 18719 candidate_events
00000400837d7800 7 85071 2 18719 candidate_events
00000400837d7800 275 76948 2 4294967295
00000400837d7800 7 41039 3 18719 candidate_events
00000400837d7800 7 37967 4 18719 candidate_events
00000400837d7800 8 67950 4 18719 candidate_events
00000400837d7800 7 33871 7 18719 candidate_events
00000400837d7800 7 59471 7 18719 candidate_events
00000400837d7800 8 8558 24 18719 candidate_events
如前所述,熱點塊通常是應用程式導致的。找出這些程式,檢查他們為什麼重複訪問相同的塊,並且做出相應的調整。
另外一個解決辦法,就是儘量將熱點塊分配到不同的hash chain連結串列,由不同的cache buffers chains latch來保護。這可以通過調整熱點塊中的行資料分佈到不同的塊中來實現。新的塊有不同的塊地址,這樣原來在同一個hash chain上的資料就可能會分佈到其他不同的hash chain上。改變塊中行資料的分佈有很多方法,包括:
n 通過rowid刪除並且重新插入某些行。
n 將表exp出來,加大 pctfree,然後再imp表。這樣會使每個塊中的資料減少,使資料分佈到更多的塊上。同時,也會導致佔用更多的空間,全表掃描的效能也會受到影響。
n 儘量減每個塊中的記錄數。首先需要dump一些資料塊來分析現在每個塊中的記錄數。Dump出來的跟蹤檔案中,nrow就是塊中的記錄總數。然後exp表,再truncate表,在表中插入你想要在每個塊中儲存的條數的記錄,然後使用alter table table_name minimize records_per_block,再truncate表,最後imp回資料即可。
n 可以考慮減少塊的大小。從oracle9i開始,資料庫可以支援不同的塊大小。例如當前塊大小為16k,你可以將表及其索引移動塊大小為8k的表空間中。這也會對全表掃描造成負面影響。並且,多個塊大小也會使得管理更復雜。
另外,從oracle9iR2開始,也可以通過增加隱含引數_spin_count的值來解決熱點塊導致的cache buffers chains latch爭用。最後,也可以通過隱含引數_db_block_hash_buckets來增加hash bucket的數量,從oracle8i開始,一般不建議採用這種辦法,如果實在要用,請保證_db_block_hash_buckets的值為一個質數,否則,oracle也會自動採用大於你提供的值的最小的質數值。
Cache buffers chains latch爭用原因三 ―― 過長的hash chain
多個資料塊可能分配到同一個hash bucket上。這些塊組成一個連結串列(hash chain)。在一個大型系統中,一個hash bucket中可能有上百個資料塊。從一個hash chain連結串列中搜尋某個塊,需要獲得cache buffers chains latch,序列的進行。如果連結串列太長,使得latch持有時間相應增加,可能導致其他程式請求cache buffers chains latch失敗。
在oracle8.0之前,由於hash latch,hash bucket,hash chain之間是1:1:1的關係,很容易計算一個hash chain的長度,等於一個latch需要保護的資料塊數。通過下面的查詢可以知道一個hash chain上的資料塊數。一般而言,一個hash chain連結串列上超過10個資料塊就認為太長了。
Select hladdr, count(*)
from x$bh
group by hladdr
order by 2;
從oracle8i起,hash latch和hash bucket之間的關係變成了1:m。這樣就很難計算某個hash chain具體的長度了。只能計算一個hash latch需要保護多少個資料塊。而一個hash latch可能同時保護多個hash chain連結串列。上面的那個查詢的結果變成了每個hash latch需要保護的資料塊數。在你判斷一個hash latch保護的資料塊是否過量之前,需要先得到hash latch和hash bucket的比值。在下面的例子中,每個hash latch保護125個hash chain。如果你想要每個hash chain上不超過10個資料塊,則每個hash latch保護的資料塊不能超過1250個。通過隱含引數_db_block_hash_buckets可以增加hash bucket的數目,這樣可以減少每個hash chain上的資料塊數(因為hash bucket和hash chain之間是1:1的關係)。從oracle8i開始,一般不建議這麼做。
_db_block_hash_buckets = 128021
_db_block_hash_latches = 1024
ratio = 128021 / 1024 = 125
Cache buffers lru chain latch
除了hash chain,緩衝頭同樣組成一個列表,這個列表指向其他的列表比如lru,lruw和ckpt-q。Lru和lruw列表並不是什麼新東西,他們是資料緩衝區中最早的兩個連結串列。Lru列表包含了不同狀態的快取塊,而lruw就是俗稱的“髒表”,只包含髒資料塊。Lru和lruw列表是互斥的,他們合稱一個工作集(a working set)。每個工作集由一個cache buffers lru chain latch保護。換句話說,資料緩衝區中工作集的個數是由cache buffers lru chain latch的個數決定的。通過內部檢視x$kcbwds (kernel cache buffer working sets descriptors)可以知道工作集的個數。我們注意到x$kcbwds 的set_latc的值就是v$latch_children的addr列。
lru + lruw = a working set
Select set_id, set_latch
from x$kcbwds
order by set_id;
set_id set_latc
---------- --------
1 247e299c
2 247e2e68
3 247e3334
4 247e3800
5 247e3ccc
6 247e4198
7 247e4664
8 247e4b30
select addr
from v$latch_children
where name = ’cache buffers lru chain’
order by addr;
addr
--------
247e299c
247e2e68
247e3334
247e3800
247e3ccc
247e4198
247e4664
247e4b30
一般來講,當程式需要查詢可用的快取空間時,需要訪問lru列表。後臺程式DBWn則會將lruw列表中的乾淨塊移到lru列表中,也會將lru中的髒塊移到lruw列表中。在一個工作集中進行以上的任何操作都需要先獲得cache buffers lru chain latch。
各個資料緩衝區中(包括不同塊大小的緩衝區,keep池和recycle池),每個緩衝區至少需要有一個cache buffers lru chain latch,而一個DBWn程式可能需要多個latch。否則,一個工作集就可能變得很長。在oracle9i和oracle10g中,cache buffers lru chain latch的個數預設是cpu個數的4倍,如果,db_writer_processes大於4,則等於cpu的個數乘以db_writer_processes。可以通過隱含引數_db_block_lru_latches來調節cache buffers lru chain latch的個數。
Cache buffers laru cahin latch的爭用,主要表現為由於低效的sql語句導致資料緩衝區過度活躍。全表掃描和對某些選擇性較差的大索引的反覆掃描是造成cache buffers laru cahin latch爭用的主要原因。解決辦法是,查詢latch free等待事件中關於cache buffers lru chain latch相關的sql語句(在oracle10g中,已經變成一個獨立的cache buffers lru chain等待事件),優化這些sql,降低其物理讀和邏輯讀。
Row cache objects latch
Row cache objects latch用來保護資料字典緩衝區(row cache的名字主要是因為其中的資訊是按行儲存的,而不是按塊儲存)。程式在裝載、引用或者清除資料字典緩衝區中的物件時必須獲得該latch。在oracle8i之前,這是一個獨立latch。從oracle9i起,由於引入了多個子共享池的新特性,存在多個row cache objects子latch。Oracle10g中,該latch也有了一個獨立的等待事件:row cache objects。
從oracle7.0起,資料字典緩衝成為了共享池的一部分。而在7.0之前,每個資料字典物件都是由獨立的dc_*初始化引數控制。Oracle7.0的這個改變也意味著,不能再直接的調整資料字典緩衝,而只能通過調整shared_pool_size來間接的調整。V$rowcache檢視包含了每個資料字典物件的統計資訊。你可以通過下面的查詢發現最熱的資料字典物件。
Select cache#, type, parameter, gets, getmisses, modifications mod
from v$rowcache
where gets > 0
order by gets;
cache# type parameter gets getmisses mod
------ ----------- ------------------ ---------- ---------- ------
7 subordinate dc_user_grants 1615488 75 0
2 parent dc_sequences 2119254 189754 100
15 parent dc_database_links 2268663 2 0
10 parent dc_usernames 7702353 46 0
8 parent dc_objects 11280602 12719 400
7 parent dc_users 81128420 78 0
16 parent dc_histogram_defs 182648396 51537 0
11 parent dc_object_ids 250841842 3939 75
對資料字典緩衝區的調節手段是有限的。最好的辦法是降低對前面的查詢結果中一些熱點資料字典物件的訪問。舉個例子,如果對某些sequence訪問頻繁,可以將考慮將這些sequnce快取在記憶體中。包含多個基表連線或者基於檢視的檢視可能導致該latch爭用。一般的解決辦法是增加shared_pool_size的值。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16179598/viewspace-627155/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Latch free等待事件一事件
- latch free等待事件事件
- Latch free等待事件(轉)事件
- Latch free等待事件三事件
- Latch free等待事件四事件
- Latch free等待事件二事件
- Latch free等待事件三(轉)事件
- Latch free等待事件四(轉)事件
- Latch free等待事件二(轉)事件
- latch free 等待事件說明事件
- latch free 等待事件說明(轉)事件
- latch free 等待事件的診斷語句事件
- latch等待事件彙總事件
- latch 相關等待事件事件
- latch free事件的整理事件
- Cache Buffer Chain Latch等待事件AI事件
- latch free事件的整理(轉)事件
- latch:library cache lock等待事件事件
- cache buffer lru chain latch等待事件AI事件
- [20170324]cpu 100%,latch free等待分析
- ORACLE等待事件latch: cache buffers chainsOracle事件AI
- 【效能調整】等待事件(九) latch原理事件
- 等待事件_cache_buffers_chains_latch事件AI
- 等待事件_cache_buffers_lru_chain_latch事件AI
- [20211229]再論19c latch free等待事件分析.txt事件
- [異常等待事件latch undo global data]分析事件
- 轉_診斷latch:shared pool等待事件事件
- buffer cache與相關的latch等待事件事件
- [重慶思莊每日技術分享]-free buffer waits 等待事件AI事件
- 【效能調整】等待事件(十) 10g中的latch等待事件
- 處理 latch_cache_buffers_chains等待事件一例AI事件
- oracle library cache相關的等待事件及latchOracle事件
- 長時間latch free等待——記一次系統異常的診斷過程
- 模擬產生CBC LATCH與buffer busy wait等待事件AI事件
- 12c設定RESULT_CACHE_MODE=MANUAL發生'Result Cache:RC Latch'型別的Latch Free等待型別
- oracle等待事件一Oracle事件
- Oracle 等待事件 一Oracle事件
- oracle一次卡頓案例(六)-latch freeOracle