Oracle Dba必須瞭解的buffer busy waits等待

wei-xh發表於2012-07-24

Buffer Busy Waits是怎麼產生的?

作為一個Oracle DBA,如果你從未遇到過Buffer Busy Waits等待,那麼你算不上一個真正的Oracle Dba。

Buffer Busy Waits是Oracle 資料庫非常常見的一個等待,特別是在併發寫比較頻繁的環境裡。說起為什麼會產生這個等待,首先要描述下,Oracle讀寫資料塊的過程:

  1. 首先依據資料塊地址計算出(Hash演算法)資料塊所在的Hash Bucket。

  2. 根據桶的編號,計算出保護這個桶的CBC Latch,然後申請CBC Latch,查詢資料塊在不在桶裡(記憶體裡),我們這裡假設在記憶體裡。

  3. 讀取/修改資料塊。

  4. 釋放CBC Latch。

以上的描述看似是非常通暢,但是存在一個問題,CBC Latch的持有是排他的,如果在排他持有CBC Latch的情況下,讀取資料塊內容,那麼這個Latch的持有時間就會比較長,因為相對於Latch的獲取和釋放這種CPU原子操作,讀取資料塊的內容是非常耗時的,因此在持有CBC Latch的情況下,讀取資料塊,對於讀寫頻繁的資料庫/塊,那麼勢必會造成CBC Latch的爭用。

為了解決這個問題,Oracle引入了buffer pin的功能。

我們有必要對讀取資料塊的內容重新做下描述,大致步驟如下:

  1. 首先依據資料塊地址計算出(Hash演算法)資料塊所在的Hash Bucket。

  2. 然後申請CBC Latch,查詢、定位到資料塊

  3. 以S/X模式獲取資料塊的buffer pin。(讀取獲得S模式,修改獲得X模式,S和S模式具有相容性,S和X、X和X模式不具有相容性)

  4. 釋放CBC Latch

  5. 在Pin的保護下,讀取/修改資料塊

  6. 獲得CBC Latch

  7. 釋放Buffer Pin

  8. 釋放CBC Latch

看似步驟複雜了,CBC Latch獲取/釋放了兩次,可是卻大大的提高了併發度。

上面描述的步驟裡,持有CBC Latch的目的變得單純,只是為了增加Buffer的Pin模式,然後依靠Pin的模式相容性來保護資料塊,例如:S和S模式的Pin是相容的,可以併發的讀取,S和X模式是不相容的,後來的會話需要產生等待。

雖然Latch的持有是排他的,但是這個時間極端,引起爭用的可能性不大,如果大家都是來讀資料塊的,那麼Buffer Lock的S模式之間都是具有相容性的,不會產生爭用。但是同一個時刻,如果一個程式以S模式持有了資料塊的Buffer Lock,另一個程式想以X模式持有,那麼就會出現爭用,因為道理很簡單,S模式的Buffer Pin和X模式的Buffer Pin不相容。

同理,兩個同時欲修改同一個資料塊的程式,也會遭遇Buffer Pin衝突.這個衝突以ORACLE 等待事件表示出來就是Buffer Busy Waits,也就是說Buffer Busy Waits等待的本質是buffer pin的爭用導致的。

我們平時經常說讀不阻塞寫,寫不阻塞讀,那是在物理的資料塊級別,在記憶體裡,讀寫/寫寫在同一個時刻都是互相阻塞的。只有讀讀不阻塞。

為了方便理解,上面很多步驟做了簡化,下面對某些點做些補充:

  • 一旦你Pin住了一個資料塊,不需要立即去UNPin(移除Pin)它。ORACLE認為你的本次呼叫後還有可能去訪問這個資料塊,因此保留了Pin,直到本次呼叫結束再UNPin。

  • Oracle在對唯一索引/undo塊/唯一索引的回表/索引root、branch塊的設計上,在訪問(讀取)的時候,獲取的是共享的CBC Latch,不需要去Pin資料塊,在持有共享CBC Latch的情況下讀取資料塊。可能的原因是這些塊修改的可能性比較小,因此Oracle單獨的採用這種機制。因此對於普通資料塊的讀取都是需要獲取2次CBC Latch,而對於這種特殊的資料塊,只獲取一次共享CBC Latch就可以了。

  • 我們上面所說的情況都是在資料塊已經存在在記憶體裡的情況。如果資料塊不在記憶體,有可能會產生READ BY OTHER SESSION爭用等待。

  • 上面描述只符合10G後的版本。在10G前讀讀也會產生Buffer BUSY WAITS,10G後把這方面的Buffer BUSY WAITS歸到了READ BY OTHER SESSION等待裡。


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

相關文章