Oracle 鎖機制探究

官網網址參考:數據庫

11.2
10.2

1、Oracle數據庫的鎖類型:緩存

根據保護的對象不一樣,Oracle數據庫鎖能夠分爲如下幾大類:    
一、DML鎖(data locks,數據鎖),用於保護數據的完整性;    
二、DDL鎖(dictionary locks,字典鎖),用於保護數據庫對象的結構,如表、索引等的結構定義;    
三、內部鎖和閂(internal locks and latches),保護數據庫的內部結構。 
 
2、接下來依次討論以上三種鎖結構:
1.DML鎖
DML鎖主要包括TM鎖和TX鎖,其中TM鎖稱爲意向鎖或表級鎖,TX鎖稱爲行級鎖或事務鎖。咱們能夠認爲Oracle只有以下6種LMODE的鎖,只是根據鎖定的對象不一樣而有不一樣的名稱,如6號的X鎖,既能夠是用於鎖表的TM鎖,也能夠是TX鎖,也能夠是DDL鎖。
1.1 TM鎖(也叫意向鎖/表級鎖)
TM鎖包含以下類型:

TM鎖的兼容性以下:(Y表示兼容,N表示衝突)session

1.2 TX鎖數據結構

TX鎖只包含一種類型的鎖:
TX的本義是Transaction(事務),當一個事務第一次執行數據更改(Insert、Update、Delete)或使用SELECT… FOR UPDATE語句進行查詢時,它即得到一個TX(事務)鎖,直至該事務結束(執行COMMIT或ROLLBACK操做)時,該鎖才被釋放。
在同一個事務中,不管是鎖定一行,仍是一百萬行,對於Oracle來講鎖開銷是同樣的。這點可能與其餘數據庫不同(例如SQL Server),緣由是針對Oracle的每行數據都有一個標誌位來表示該行數據是否被鎖定。這樣就極大的減少了行級鎖的維護開銷,也不可能出現鎖升級。數據行上的鎖標誌一旦被置位,就代表該行數據被加X鎖。
注意TX鎖在v$lock的lmode也是6,可是這個6與TM鎖的6號X鎖只是由於鎖定的對象不一樣而被叫作了TX鎖。

1.3 舉例說明架構

當發出一個DML命令後會話獲取一個3號的TM鎖,和一個針對特定行的6號TX鎖。
行級只有X鎖,且鎖模式爲6,再次重申這裏的6並非指TM的6號表鎖。
此外Oracle一個事務中不管鎖定多少行只會獲取一個TX鎖(沒有鎖升級),但有多少個表對象就會獲取多少個TM表級鎖。
驗證以下:

查詢鎖的語句爲:併發

1
select sid,type,id1,lmode,request,block from v$ lock l where sid in ( select session_id from v$locked_object) and type in ( 'TM' , 'TX' ) order by 1;

1.4 DML鎖的總結:oracle

讀永遠不會阻止寫。但有惟一的一個例外,就是select ...for update。
寫永遠不會阻塞讀。當一行被修改後,Oracle經過回滾段提供給數據的一致性讀。
注意:
以上讀寫操做不會互相阻塞是指在DML鎖級別不會,但在內存中依然會發生內部閂鎖的爭用形成讀被阻塞。例如DDL鎖可能會形成嚴重的library cache lock等待,致使select語句被阻塞。再好比熱塊爭用也會形成寫阻塞讀,只不過表現是buffer busy waits而已。

2.DDL鎖
高併發

重點:DDL是保護表結構定義的。
DDL命令發出時,Oracle會自動在被處理的對象上添加DDL鎖定,從而防止對象被其餘用戶所修改。當DDL命令結束之後,則釋放DDL鎖定。
DDL鎖定不能顯式的被請求,只有當對象結構被修改或者被引用時,纔會在對象上添加DDL鎖定。
並非全部DDL都會觸發DDL鎖,例如如今的建立索引語句,就只會獲取一個S模式的TM鎖,所以不會阻塞讀。而online模式建立索引的語句則只會獲取一個2號的TM鎖,所以連DML也不會被阻塞。
須要注意的是DDL總會提交,即使是執行不成功也是如此,所以若是在事務中執行了DDL語句會致使全部事物被提交。驗證很容易,在一個窗口執行一條delete而後執行DDL,你會發現記錄被不可逆轉的刪除了,RollBack無效。所以針對事務中的DDL請務必使用自治事務實現。
DDL鎖有3種:
2.1 排他DDL鎖  --即6號的TM鎖(Exclusive DDL Locks)
通常對錶的DDL語句都會獲取一個X模式的TM鎖,這是爲何在表結構更改時只能查詢不能修改的緣由。
 
2.2 共享DDL鎖(Share DDL Locks)
共享DDL鎖的常見情形爲建立存儲過程時,會嘗試爲全部涉及到的表添加共享DDL鎖,這會容許相似的DDL操做併發,但會阻止全部想要獲取排他DDL鎖的會話(即更改表結構的會話)。
--我覺的能夠認爲這就是4號的TM表鎖。
 
2.3 可中斷解析鎖(Breakable Parse Locks)
會話解析一條SQL或PLSQL代碼塊時,對於該語句引用的每個對象都會施加解析鎖,目的在於:若是以某種方式刪除或修改了引用對象,能夠將共享池中已經解析的緩存語句無效刷出。
之因此叫作可中斷解析鎖,是由於這種鎖優先級很低可能會被其餘互斥DDL操做打斷。
每一個SQL在解析時都會獲取一個可中斷解析鎖,只要SQL語句還在shared pool中,這個鎖就一直存在。
Library cache lock 和 Library cache pin就是屬於可中斷解析鎖,lock是針對父遊標句柄和子游標句柄的保護體,pin是針對父子游標的保護體。前者有三種模式:1 null,2 S,3 X 後者只有2 S,3 X兩種模式。
 
3.內部閂鎖機制
Latches:
可譯做閂或者栓,這是一種很是低級別的序列化結構,用於協調併發會話對於共享數據結構、文件等的訪問。
閂能夠防止併發會話破壞共享的內存資源,幾個很是典型的場景是:
  • 多個會話同時修改數據
  • 讀取的數據正在被其餘會話修改
  • 從新分配內存
可能在這裏會和事務鎖混淆,但事務鎖是鎖定邏輯結構的,如表和行,可是閂倒是鎖定物理結構的,如內存中的數據塊、執行計劃鏈表等等。多個會話對於同一個對象的訪問就須要閂來保護了,例如對於同一個數據塊中不一樣行的訪問就須要latch來保護,而閂的存在時間是極短的,所以能夠實現高併發(其實Oracle高併發並不是是真正的併發而是latch釋放速度極快的串行訪問)。
一般在SGA中一個latch能夠保護多個對象,例如DBWn和LGWR進程從SGA中分配內存以便建立新的數據結構,爲了防止衝突進程會使用一種叫作shared pool latch的閂來序列化分配操做,在內存分配完畢後其它進程可能會須要訪問shared pool中的其餘區域如library cache,此時閂只會鎖住library cache而非整個shared pool。
一般狀況下oracle進程獲取閂的時間極短,一個簡單的查詢都會有成千上萬次的閂的獲取和釋放,是徹底不能由用戶控制的。
閂的數目的增多,意味着併發量增大,能夠經過v$latch視圖來查看閂的使用狀況,包括每種閂被請求和等待的次數。
Mutex:(Mutual exclusion object)
能夠譯做互斥體,這種結構很相似於閂,區別在於一種mutex只保護一種對象,而一種閂一般會保護多種對象。
mutex的優點在於:
  • mutex能夠減小latch爭用
  • mutex比latch佔用更少的內存
  • share mode模式的mutex容許多個會話併發使用
其餘內部鎖:
這些是比mutex和latch更復雜的結構,oracle數據庫使用如下幾種內部鎖:
1.Dictionary cache locks
2.File and log management locks
3.Tablespace and undo segment locks
這幾種鎖的解釋有興趣能夠到官網看,平時基本觀察不到,後兩種基本都在多實例時出現。
 
拓展說明:
上邊談到了Library cache lock和Library cache  pin,這裏稍微解釋下:
1、首先咱們以Oracle 10.2以前版本做爲基準來解釋:主要來自於《Oracle8i Internal Services》一書的第四章
****************************************
Library cache的包含不少cache部分,它包含PLSQL代碼塊的、解析樹、SQL執行計劃等,它還包含一個由SQL引用的DIANA的數據庫對象,此對象被用於進行PLSQL塊的編譯以及SQL解析和執行,儘管數據字典中也包含此類信息。此外library cache也包含例如同義詞轉換、依賴追蹤等信息,固然還有library cache lock/pin等內存閂鎖。
Library cache lock和Library cache  pin屬於可中斷解析鎖,Library cache lock有NULL、S、X三種模式,Library cache pin有S和X兩種模式,在解析SQL時會話獲取S模式的Library cache lock,解析完畢後轉爲NULL模式。若是有DDL操做更改了語句涉及的數據庫對象,那麼依賴於此數據庫對象的全部library cache objects都會失效,失效過程就是失去NULL模式的library cache lock的過程。
****************************************
接下來先放一張圖:
這是library cache中主鏈表的簡易結構圖,每一個hash bucket對應一個父遊標句柄的鏈表,LCO表示library cache objects,是父遊標或者子游標。父子游標是一對一或者一對多的關係。
在瞭解了以上基本常識的狀況下,再來看涉及的內存栓鎖:
進行硬解析的會話須要獲取library cache latch(只有獨佔模式,無隊列)來生成父遊標句柄,待添加X模式library cache lock後釋放library cache latch進行父遊標句柄構造,構造父遊標句柄完畢後獲取X模式的library cache pin來構造父遊標,接下來獲取X模式的library cache lock生成子游標句柄,最後獲取X模式library cache pin構造子游標完成硬解析。
若是是在已經存在的父遊標上進行硬解析那麼就會添加S模式的父遊標句柄library cache  lock來獲取X模式的父遊標library cache pin,以後獲取X模式的library cache lock/pin完成硬解析。
軟解析時則先獲取S模式的父遊標句柄library cache lock,而後獲取S模式父遊標library cache  pin、S模式子游標句柄library cache lock和S模式子游標library cache pin。
2、接下來討論10.2以後的的變化:
library cache pin結構被Cursor:xxx類型的mutex取代,而在11.1以後library cache latch結構也被library cache:mutex xxx類型的mutex取代了。
那麼全新的SQL硬解析時首先會在library cache:mutex X的保護下獲取X模式的library cache lock,而後釋放mutex並構造父遊標句柄,以後獲取Cursor:pin X構造父遊標,而後獲取子游標句柄library cache lock構造子游標句柄並釋放父遊標的Cursor:pin X,最後獲取Cursor:pin X完成子游標的構造從而完成硬解析。
若是是已經存在的父遊標進行硬解析,那麼首先在library cache:mutex X的保護下獲取S模式的library  cache lock,以後獲取Cursor:pin S來pin住父遊標,而後獲取X模式的library cache lock構造子游標句柄並釋放父遊標mutex,最後獲取Cursor:pin X構造子游標完成硬解析。
若是是軟解析那麼首先在library  cache:mutex X的保護下獲取S模式的library cache lock,以後獲取Cursor:pin S來pin住父遊標,最後依次找到子游標句柄和子游標。
若是發生了Cursor:pin S wait on X,那麼意味着有硬解析在發生,而且可能存在較高的version count,致使此父遊標句柄下的全部遊標沒法拿到Cursor:pin S。還有一種狀況是遊標涉及的LCO發生了DDL致使全部句柄失效,此時須要進行從新編譯獲取X模式的子游標mutex,所以其餘會話發生Cursor:pin S wait on X等待。
一樣的library cache lock等待也意味着存在硬解析,只有硬解析纔會獲取X模式的library cache lock,因爲library cache lock的獲取須要mutex的保護,相應的mutex等待也會伴生,多是library cache:mutex X或者Cursor:xxx類型的mutex,這取決於library  cache lock的等待是在父遊標句柄仍是子游標句柄上,子游標句柄較爲常見。
 
最後重要說明:
以上全部觀點除來自書本的那段以外,都是基於buffer cache鏈表的查找方式進行類推解釋的,都是基於latch/mutex是鎖獲取與釋放的保護體來解釋的,都是基於修改底層結構須要在上層添加X模式鎖來解釋的,都是基於mutex是一種極端稀缺的資源來解釋的,極可能是錯的,我這裏只是爲了創建初步的架構方便理解,就算是錯的對我來講也無所謂。
 
總結一下本身的觀點:
DML和除可中斷解析鎖以外的DDL鎖就是保護邏輯結構的結構體,而library cahce lock/pin、latch和mutex則是保護內存中物理結構的結構體,拋開DML鎖,通常來講在內存中獲取內存鎖都須要latch和mutex的保護,常見的場景就是library cache中Library cache lock的獲取須要library cache:mutex X的保護,以及Buffer pool中的buffer pin 須要cbc latch保護住hash bucket中涉及到本SQL的鏈表頭。
從名字上就能夠看出latch和mutex的保護對象,cursor: xxx這種mutex保護的是遊標, cbc latch保護的則是cache buffer chain鏈表,library cahce:mutex(之前叫library cache latch)則是用於保護library cache的,具體說來也是hash bucket的父遊標句柄鏈表,以此來獲取parent cursor handler上的library cache lock。
 
Oracle官網已經沒有太多更詳細的關於內部閂鎖的資料,更詳細的關於內部latch和mutex的運做機制和種類,參考呂海波《Oracle內核技術揭祕》和Steve Adams的《Oracle 8i Internal Services》一書。
相關文章
相關標籤/搜索