天天看點

Oracle latch 闩鎖結構 總結

以下内容太整理自網絡,完全處于學習目的,如有侵權請及時聯系我,我會立即删除。

一. Latch 說明

1.1 Latch

Latch屬于System Lock, 用于保護SGA區中共享資料結構的一種串行化鎖定機制。Latch的實作是與作業系統相關的,尤其和一個程序是否需要等待一個latch、需要等待多長時間有關。

Latch是Oracle提供的輕量級鎖資源,是一種能夠極快地被擷取和釋放的鎖,能快速,短時間的鎖定資源,防止多個并發程序同時修改通路某個共享資源,它隻工作在SGA中,通常用于保護描述buffer cache中block的資料結構。

比如SGA中,各種資料被反複從磁盤讀取到記憶體,又被重新寫回到磁盤上,如果有并發的使用者做相同的事情,Oracle必須使用一種機制,來保證資料在讀取的時候,隻能由一個會話來完成,這種保護機制就是Latch。

并發(concurrency):是說有超過兩個以上的使用者對同樣的資料做修改(可能包括插入,删除和修改)。

并行(parallel):是說将一件事情分成很多小部分,讓每一部分同時執行,最後将執行結果彙總成最終結果。

與每個latch相聯系的還有一個清除過程,當持有latch的程序成為死程序時,該清除過程就會被調用。Latch還具有相關級别,用于防止死鎖,一旦一個程序在某個級别上得到一個latch,它就不可能再獲得等同或低于該級别的latch。

Latch不會造成阻塞,隻會導緻等待。 阻塞是一種系統設計上的問題,等待是一種系統資源争用的問題。

1.2 有關SPin 的說明:

比如資料緩存中的某個塊要被讀取,我們會獲得這個塊的 latch,這個過程叫做spin,另外一個程序恰好要修改這個塊,他也要spin這個塊,此時他必須等待,目前一個程序釋放latch後才能spin住,然後修改,如果多個程序同時請求的話,他們之間将出現競争,沒有一個入隊機制,一旦前面程序釋放所定,後面的程序就蜂擁而上,沒有先來後到的概念,并且這一切都發生的非常快,因為Latch的特點是快而短暫。

SPIN 與 休眠:

休眠意味着暫時的放棄CPU,進行上下文切換(context switch),這樣CPU要儲存目前程序運作時的一些狀态資訊,比如堆棧,信号量等資料結構,然後引入後續程序的狀态資訊,處理完後再切換回原來的程序狀态,這個過程如果頻繁的發生在一個高事務,高并發程序的處理系統裡面,将是個很昂貴的資源消耗,是以Oracle選擇了spin,讓程序繼續占有CPU,運作一些空指令,之後繼續請求,繼續spin,直到達到_spin_count值,這時會放棄CPU,進行短暫的休眠,再繼續剛才的動作。

1.3 程序擷取Latch的過程:

任何時候,隻有一個程序可以通路記憶體中的某一個資料塊,如果程序因為别的程序正占用塊而無法獲得Latch時,他會對CPU進行一次spin(旋轉),時間非常的短暫,spin過後繼續擷取,不成功仍然spin,直到 spin次數到達閥值限制(這個由隐含參數_spin_count指定),此時程序會停止spin,進行短期的休眠,休眠過後會繼續剛才的動作,直到擷取塊上的Latch為止。

程序休眠的時間也是存在算法的,他會随着spin次數而遞增,以厘秒為機關,如1,1,2,2,4,4,8,8,。。。

休眠的閥值限制由隐含參數_max_exponential_sleep控制,預設是2秒,如果目前程序已經占用了别的Latch,則他的休眠時間不會太長(過長會引起别的程序的Latch等待),此時的休眠最大時間有隐含參數_max_sleep_holding_latch決定,預設是4厘秒。這種時間限制的休眠又稱為短期等待。

另外一種情況是長期等待鎖存器(Latch Wait Posting),此時等待程序請求Latch不成功,進入休眠,他會向鎖存器等待連結清單(Latch Wait List)壓入一條信号,表示擷取Latch的請求,當占用程序釋放Latch時會檢查Latch Wait List,向請求的程序傳遞一個信号,激活休眠的程序。Latch Wait List是在SGA區維護的一個程序清單,他也需要Latch來保證其正常運作,預設情況下share pool latch和library

cache latch是采用這個機制。

如果将隐含參數_latch_wait_posting設定為2,則所有Latch都采用這種等待方式,使用這種方式能夠比較精确的喚醒某個等待的程序,但維護Latch Wait List需要系統資源,并且對Latch Wait List上Latch的競争也可能出現瓶頸。

  如果一個程序請求,旋轉,休眠Latch用了很長時間,他會通知PMON程序,檢視Latch的占用程序是否已經意外終止或死亡,如果是則PMON會清除釋放占用的Latch資源。

總之, Latch擷取的流程:請求-SPIN-休眠-請求-SPIN-休眠 ... ... 占用。

1.4 Latch 和 Lock

從某種意義上說,Latch是記憶體中的資源鎖,資料庫對象(表,索引等)的鎖叫Lock。

Latch和Lock的差別:

  (1). Latch是對記憶體資料結構提供互斥通路的一種機制,而Lock是以不同的模式來套取共享資源對象,各個模式間存在着相容或排斥,從這點看出,Latch 的通路,包括查詢也是互斥的,任何時候,隻能有一個程序能pin住記憶體的某一塊,幸好這個過程是相當的短暫,否則系統性能将沒的保障,從9I開始,允許多個程序同時查詢相同的記憶體塊。

  (2). Latch隻作用于記憶體中,他隻能被目前執行個體通路,而Lock作用于資料庫對象,在RAC體系中執行個體間允許Lock檢測與通路

  (3). Latch是瞬間的占用,釋放,Lock的釋放需要等到事務正确的結束,他占用的時間長短由事務大小決定

  (4). Latch是非入隊的,而Lock是入隊的

        (5). Latch不存在死鎖,而Lock中存在。

二. Latch 争用

如果發現系統中經常由于Lock 導緻使用者等待,這時需要考慮系統在邏輯設計上是否有問題,比如多使用者對主鍵的删除或者修改,是否有使用者使用select … for update這樣的文法,外鍵是否建立索引的因素。 這些因素是需要結合系統的業務邏輯性來進行資料庫對象設計的。

如果發現系統慢是因為很多的Latch争用,就要考慮系統及資料庫自身設計上是否存在問題,比如是否使用綁定變量,是否存在熱快,資料存儲參數設計是否合理等因素。

導緻Latch争用而等待的原因非常多,記憶體中很多資源都可能存在争用。 最常見的兩類latch争用如下:

(1)共享池中的Latch争用。

 (2)資料緩沖池中的latch争用。

2.1 共享池中的Latch争用

共享池中如果存在大量的SQL被反複分析,就會造成很大的Latch争用和長時間的等待,最常見的現象就是沒有綁定變量。

最常見的集中共享池裡的Latch是 library cache。 可以通過一下SQL 來查詢:

SQL> select * from v$latchname where name like 'library cache%';

LATCH#                 NAME                                          HASH

---------- -----------------------------------------                ----------

217                library cache                                  3055961779

218                library cache lock                          916468430

219                library cache pin                            2802704141

220                library cache pin allocation         4107073322

221                library cache lock allocation         3971284477

222                library cache load lock                  2952162927

223                library cache hash chains           1130479025

在分析系統性能時,如果看到有library cache 這樣的Latch争用,就可以斷定是共享池中出現了問題,這種問題基本是由SQL語句導緻的,比如沒有綁定變量或者一些存儲過程被反複分析。

資源的争用可以通過如下SQL 來檢視:

SQL> select event,count(*) from v$session_wait group by event;

     EVENT                                                                                      COUNT(*)

----------------------------------------------------------------                  ----------

SQL*Ne tmessage from client                                                       4

Streams AQ: waiting for messages in the queue                       1

ASM background timer                                                                     1

gcs remote message                                                                      1

ges remote message                                                                      1

jobq slave wait                                                                                   1

rdbms ipc message                                                                        14

smon timer                                                                                         1

pmon timer                                                                                         1

Streams AQ: qmn slave idle wait                                                   1

class slave wait                                                                                 1

SQL*Net message to client                                                            1

Streams AQ: waiting for time management or cleanup tasks    1

Streams AQ: qmn coordinator idle wait                                        1

DIAG idle wait                                                                                     1

15 rows selected.

2.2 資料緩沖池Latch争用

通路頻率非常高的資料塊被稱為熱快(Hot Block),當很多使用者一起去通路某幾個資料塊時,就會導緻一些Latch争用,最常見的latch争用有:

(1)buffer busy waits

(2)cache buffer chain

這兩個Latch的争用分别發生在通路資料塊的不同時刻。

Cache buffer chian産生原因:當一個會話需要去通路一個記憶體塊時,它首先要去一個像連結清單一樣的結構中去搜尋這個資料塊是否在記憶體中,當會話通路這個連結清單的時候需要獲得一個Latch,如果擷取失敗,将會産生Latch cache buffer chain 等待,導緻這個等待的原因是通路相同的資料塊的會話太多或者這個清單太長(如果讀到記憶體中的資料太多,需要管理資料塊的hash清單就會很長,這樣會話掃描清單的時間就會增加,持有chache

buffer chain latch的時間就會變長,其他會話獲得這個Latch的機會就會降低,等待就會增加)。

Buffer busy waits 産生原因:當一個會話需要通路一個資料塊,而這個資料塊正在被另一個使用者從磁盤讀取到記憶體中或者這個資料塊正在被另一個會話修改時,目前的會話就需要等待,就會産生一個buffer busy waits等待。

産生這些Latch争用的直接原因是太多的會話去通路相同的資料塊導緻熱快問題,造成熱快的原因可能是資料庫設定導緻或者重複執行的SQL 頻繁通路一些相同的資料塊導緻。

Latch是簡單的、低層次的序列化技術,用以保護SGA中的共享資料結構,比如并發使用者清單和buffer cache裡的blocks資訊。一個伺服器程序或背景程序在開始操作或尋找一個共享資料結構之前必須獲得對應的latch,在完成以後釋放latch。不必對latch本身進行優化,如果latch存在競争,表明SGA的一部分正在經曆不正常的資源使用

三. 檢查Latch 的相關SQL

3.1 檢視造成LATCH BUFFER CACHE CHAINS等待事件的熱快:

SELECT DISTINCT a.owner, a.segment_name

FROM dba_extents a,

(SELECT dbarfil, dbablk

FROM x$bh

WHERE hladdr IN (SELECT addr

FROM ( SELECT addr

FROM v$latch_children

ORDER BY sleeps DESC)

WHERE ROWNUM < 20)) b

WHERE a.RELATIVE_FNO = b.dbarfil

AND a.BLOCK_ID <= b.dbablk

AND a.block_id + a.blocks > b.dbablk;

3.2 查詢目前資料庫最繁忙的Buffer,TCH(Touch)表示通路次數越高,熱點快競争問題就存在

SELECT *

FROM ( SELECT addr,

ts#,

file#,

dbarfil,

dbablk,

tch

ORDER BY tch DESC)

WHERE ROWNUM < 11;

3.3 查詢目前資料庫最繁忙的Buffer,結合dba_extents查詢得到這些熱點Buffer來自哪些對象

SELECT e.owner, e.segment_name, e.segment_type

FROM dba_extents e,

(SELECT *

FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch

WHERE ROWNUM < 11) b

WHERE e.relative_fno = b.dbarfil

AND e.block_id <= b.dbablk

AND e.block_id + e.blocks > b.dbablk;

3.4 如果在Top 5中發現latch free熱點塊事件時,可以從V$latch_children中查詢具體的子Latch資訊

FROM (SELECT addr, child#, gets, misses, sleeps, immediate_gets igets,

immediate_misses imiss, spin_gets sgets

WHERE NAME = 'cache buffers chains'

3.5 擷取目前持有最熱點資料塊的Latch和buffer資訊

SELECT b.addr, a.ts#, a.dbarfil, a.dbablk, a.tch, b.gets, b.misses, b.sleeps

FROM (SELECT *

FROM (SELECT addr, ts#, file#, dbarfil, dbablk, tch, hladdr

WHERE ROWNUM < 11) a,

(SELECT addr, gets, misses, sleeps

WHERE NAME = 'cache buffers chains') b

WHERE a.hladdr = b.addr;

3.6 利用前面的SQL可以找到這些熱點Buffer的對象資訊

SELECT distinct e.owner, e.segment_name, e.segment_type

3.7 結合SQL視圖可以找到操作這些對象的相關SQL,然後通過優化SQL減少資料的通路,或者優化某些容易引起争用的操作(如connect by等操作)來減少熱點塊競争

break on hash_value skip 1

SELECT /*+ rule */ hash_value,sql_text

FROM v$sqltext

WHERE (hash_value, address) IN (

SELECT a.hash_value, a.address

FROM v$sqltext a,

(SELECT DISTINCT a.owner, a.segment_name, a.segment_type

FROM (SELECT dbarfil, dbablk

WHERE a.relative_fno = b.dbarfil

AND a.block_id <= b.dbablk

AND a.block_id + a.blocks > b.dbablk) b

WHERE a.sql_text LIKE '%' || b.segment_name || '%'

AND b.segment_type = 'TABLE')

ORDER BY hash_value, address, piece;