latch free 等待事件說明

jss001發表於2009-02-11
當程式想要獲取鎖存器而此時該鎖存器正被其他程式持有時產生Latch Free(鎖存器空閒)等

待事件,類似於排隊,Oracle使用鎖存器來保護資料結構。一次只能在一個程式在獲得鎖存器後

修改或檢查資料結構。其他需要訪問該資料結構的程式必須等到它們獲得鎖存器後。不同於排隊

的是,請求鎖存器的程式不需要在佇列中等待。如果獲取鎖存器失敗,則程式僅僅等待一小段時

間就可以再次請求鎖存器。這一小段等待時間成為“自旋”(spin)。如果在一次或多次自旋重複

(spin iterations)之後還沒獲取鎖存器,程式就休眠一小段時間,然後再次嘗試獲取鎖存器,

接下來休眠更長一段時間,直到獲得鎖存器。

最常見的鎖存器有:cache buffer chains(快取記憶體緩衝區鏈)、library cache(快取記憶體)

和shared pool(共享池)。

1、等待引數

latch free的等待引數描述如下:

◎ P1 程式等待的鎖存器地址。

◎ P2 鎖存器號,同v$latchname.latch#

要查詢等待鎖存器的名稱,可以是喲功能如下SQL語句:

SELECT *

FROM v$latchname

WHERE latch# = &P2_Value;

◎ P3 嘗試的次數;顯示程式試圖獲取鎖存器的次數計數器。



2、等待時間

該時間的等待時間呈指數級增長。他不包含程式為鎖存器自旋(spin) 花費的時間。



以不等待模式獲取的鎖存器在IMMEDIATE_GETS和IMMEDIATE_MISSES列中統計。

透過願意等待模式獲取鎖存器在GETS和MISSES列中有統計。特殊鎖存器的GETS列在每次程式

透過願意等待模式請求該鎖存器時遞增。

如果鎖存器不能用,那麼程式會在CPU上自旋(spin)一小段時間,重新嘗試該鎖存器。

v$system_Event檢視中的latch free等待事件的total_waits統計追蹤程式以願意等待模式

無法獲得一個鎖存器的次數。v$latch檢視中特殊鎖存器的sleeps統計追蹤程式在鎖存器上睡眠

的次數。因為程式在_SPIN_COUNT次數後無法獲得鎖存器時沒有別的事可做只好睡眠,total_times

應該等於sleeps的綜合,然而,很多時候total_times大於sleeps的總合。這是因為sleeps統計

只有在鎖存器GET操作成功才更新,而不是每次嘗試是更新。

因為latch free等待事件總是很短,所以可以看到total_waits的一個較大的數字,這是計

數器在一段短時間內發生的等待事件。



3、常見原因、診斷和動作

鎖存器徵用表名另一個程式持有該鎖存器過長的時間。當結合高需求量,這種爭用帶

來的影響將會擴大,從而明顯地降低效能。鎖存器爭用在高度併發的環境中很普遍。可以

根據如下SQL檢視程式競爭的熱鎖存器:

SELECT NAME,

Gets,

Misses,

Immediate_Gets,

Immediate_Misses,

Sleeps

FROM V$latch

ORDER BY Sleeps;



◎ shared pool鎖存器和library cache鎖存器的爭用——解析

shared pool鎖存器和library cache鎖存器的爭用主要是由於緊密的硬解析。過多

的硬解析通常出現在主要使用帶有字面值的SQL語句的應用程式中。應解析是代價

昂貴的才做,並且在解析期間必須持有子library cache鎖存器。



①.使用下面語句查資料庫中硬解析的數量:

SELECT a.*,

SYSDATE - b.Startup_Time Days_Old

FROM V$sysstat a,

V$instance b

WHERE a.NAME LIKE 'parse%';

②.發現執行許多硬解析的當前會話:

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;

③.標識作為繫結變數的合適候選的literal 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;

④.正確的設定SESSION_CACHED_CURSOES引數:

每當SQL語句到達時,Oracle檢查該語句是否已經在庫快取記憶體中。如果是的話,

只需要很少的開銷就可以執行該語句;這種程式被稱為軟解析。在硬解吸不行時,軟

解析也不好。library cache鎖存器在軟解析中獲得。Oracle仍然必須檢查語句的語法

和語義,除非該語句快取記憶體在會話的遊標快取記憶體中。透過正確的設定

SESSION_CACHED_CURSOES引數,可以減少library cache鎖存器持有時間。然而最好的

方法是減少軟解析的數量,這隻可透過應用程式完成。

透過在v$sqlarea檢視中查詢帶有大量parse_calls的語句,你可以找到令人不

愉快的語句。

如果發現資料庫具有長共享池空閒列表,並且應用程式使用literal SQL,那麼就

應該考慮減少SHARED_POOL_SIZE。這將減少share pool鎖存器的爭用。

也應該使用dbms_shared_pool.keep過程釘住共享池中可重用的物件。

v$db_object_cache檢視具有儲存相關物件的資訊。



◎ library cache鎖存器的爭用——帶有高版本數的語句

Oracle使用多個子遊標來區分一些SQL語句,這些SQL語句具有相同的字元,但是不能

被共享,因為他們引用不同的底層物件。例如:如果資料庫有三個Customer表,並且

每個表屬於不同的模式,那麼每個擁有者釋出的SELECT * FROM Customer語句將具有

相同的雜湊值,但是具有不同的子段數量。當被解析語句雜湊值匹配帶有高的子段數

或版本數的語句雜湊值時,Oracle必須比較語句和所有的現有版本。必須在檢查期間

持續持有library cache鎖存器,著可能造成其他程式無法實現他們的library cache

鎖存器請求。透過在資料庫中使用唯一的物件名,可以最小化這個問題。

查詢列出v$sqlarea中版本數大於20的所有SQL語句:

SELECT Version_Count,

Sql_Text

FROM V$sqlarea

WHERE Version_Count > 20

ORDER BY Version_Count,

Hash_Value;



◎ cache buffer chains鎖存器

在將資料讀入SGA時,他們的緩衝區頭被防止在懸掛雜湊儲存桶的連結串列中(雜湊鏈)。

這種記憶體結構由大量子cache buffers chains鎖存器(也稱雜湊鎖存器或CBC鎖存器)

保護。希望在新增、刪除、搜尋、檢查、讀取、或修改塊的程式必須首先獲得cache

buffers chains鎖存器,從而保護鏈上的緩衝區。這樣就可以保證獨佔訪問,並防

止其它程式接下來讀取或改變同一個鏈。為了完整性犧牲了併發性。透過設定

_DB_BLOCK_HASH_LATCHS引數可以調整雜湊鎖存器數量。

如下SQL取例項中雜湊鎖存器的數量:

SELECT COUNT(DISTINCT(Hladdr)) FROM X$bh;



①.cache buffers chains鎖存器的爭用——底效率的SQL語句

低效率的SQL語句是cache buffers chains鎖存器爭用的主要原因。當和高併發

率混合在一起時,花費在latch free等待事件上的時間可能更多。在某些環境中,

應用程式開啟執行相同的低效率SQL語句的多個併發會話,並且這些SQL語句都沒法得

到相同的資料集,這種情況下相當普遍。

如果集註下面3個方面,你可以做的很好:

◆ 每個邏輯讀取需要一個latch gey操作和一個CPU

◆ 從latch get例程中獲得的唯一方法是獲得鎖存器

◆ 在任意時刻,只有一個程式可以擁有cache buffer鏈,並且這個鎖存器覆蓋

許多資料塊,另一個程式可能需要其中一些資料塊。



②.cache buffers chains鎖存器的爭用——熱塊

熱塊(hot block)是cache buffer chains鎖存器爭用的另一個常見原因。當多個

會話重複訪問一個或多個由同一個子chche buffer chains鎖存器保護的塊時,熱塊

就產生。這主要是一種應用程式問題。在大多數情況下,增加cache buffer chains

鎖存器的數量對效能的改變沒多大幫助。這是因為塊被雜湊為雜湊儲存桶和基於塊地

址和雜湊儲存桶數量的鏈,而不是基於cache buffer chains鎖存器的數量。如果塊

地址和雜湊儲存桶的數量保持不變,則可能有少數熱塊仍然被一個cache buffer chains

鎖存器覆蓋,除非鎖存器數量極大的增加。

捕獲參與爭用的SQL語句:

-- Using the P1RAW from the above example (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 = '&P1RAW_Value'

UNION

SELECT Hladdr,

File#,

Dbablk,

Tch,

Obj,

NULL

FROM X$bh

WHERE Obj IN

(SELECT Obj

FROM X$bh

WHERE Hladdr = '&P1RAW_Value'

MINUS

SELECT Object_Id

FROM Dba_Objects

MINUS

SELECT Data_Object_Id FROM Dba_Objects)

AND Hladdr = '&P1RAW_Value'

ORDER BY 4;



展開塊的方法:

◆ 透過ROWID刪除並且重新插入一些行

◆ 輸出表,較大的增加PCTFREE,並且輸入資料。這可以最小化每個塊的行數量,

將他們展開到多個塊上。當然這是以儲存空間作為代價,並且全表掃描會更慢。

◆ 最小化表中每個塊的記錄數量。這涉及轉儲少量資料塊,用於獲得每個塊的當

前理想行數。手工插入你確定合適的行數,然後釋出命令:

ALTER TABLE table_name MINIMIZE RECORED_PER_BLOCK。擷取表和輸入資料。

◆ 對於索引,對於較高的PCTFREE值可以重建他們,需要注意的是這種方法可能

增加索引的高度。

◆ 考慮見效塊大小。這將對全表掃描帶來極大的負面影響。



③.cache buffers chains鎖存器的爭用——長雜湊鏈

多個資料塊可能被雜湊到同一個雜湊儲存桶,他們和指標一起被連線到屬於這個

雜湊儲存桶的雜湊鏈上。對於大型資料庫,雜湊鏈上塊的數量可以達到數百個。程式

不得不順序的掃描雜湊以獲得所需的塊,同時持有cache buffers chains鎖存器不變。

我們稱之為“追趕鏈”。當掃描長鏈時,鎖存器必須被持有更廠的時間,並且可能造

成另一個程式無法實現她的cache buffers chains鎖存器請求。

一直到Oracle 8.0,我們可以很容易地確定特定的雜湊鏈長度,因為雜湊鎖存器、

雜湊儲存桶和雜湊鏈之間的關係是1:1:1,雜湊鏈的長度等於有鎖存器保護塊的數量。

下面查尋報告每個雜湊上塊的數量,帶有10個或更多塊的鏈為長鏈。

SELECT Hladdr,

COUNT(*)

FROM X$bh

GROUP BY Hladdr

ORDER BY 2;

透過使用_DB_BLOCK_HASH_BUSH_BUCKETS引數增加雜湊儲存桶的數量,可以減少散

列的長度:

_DB_BLOCK_HASH_BUCKETS = 128021

_DB_BLOCK_HASH_LATCHES = 1024

Ratio = 128021 / 1024 = 125[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/18921899/viewspace-1017203/,如需轉載,請註明出處,否則將追究法律責任。

相關文章