Oracle事務原理探究1--oracle核心技術讀書筆記五,oracle1--oracle
1. 衝突解決
假如有一個系統只有你和我兩個使用者,並且我們都在持續對系統中一小部分資料做修改和查詢操作。
如果你正在資料庫中做一批修改操作,而我正在做查詢,我一定不能看到你所做的修改,直到你告訴我可以看到你所做的所有更改才行(你提交了事務)。因此在oracle內部,必須有一個高效的辦法來識別哪些資料我可以看到,哪些資料我不可以看到。
從相反的角度來看,在你提交事務的時候,你需要一種高效的機制讓其他所有人能夠看到事務已經提交(也就是要告訴別人你所有修改過的資料都是可見的了)。更極端一點的情況是,你可能需要決定復原事務,這樣的話,你也需要一種高效的機制能夠關聯上所有的undo記錄,按產生的順序排序,從而可以按相反的順序復原這些更改。
2. 事務與undo
建立資料庫的時候,必須建立一個undo資料表空間。同時,oracle會在undo資料表空間中自動建立多個undo段,隨著資料庫負載的變化自動新增,擴大和收縮。
交易管理起始於undo段,並以此為中心。undo段的第一個塊(段頭塊)包含如下結構:擴充映射,擴充控制頭(跟其他類型的段頭塊一樣),事務表,事務控制區(特殊的結構)。事務表的大概結構如下:
TRN TBL:
index state cflags wrap# uel scn dba nub cmt
0X00 9 0X00 0X2013 0X001b 0X0000.016f1fc1 0X0180083e 0X00000001 1302762364
0X01 9 0X00 0X2014 0X001a 0X0000.016f1f54 0X0180083e 0X00000001 1302762364
0X02 10 0X80 0X2013 0X001d 0X0000.016f20fc 0X0180083e 0X00000001 0
0X03 9 0X00 0X200c 0X001c 0X0000.016f20d8 0X0180083e 0X00000001 1302762364
0X04 9 0X00 0X200f 0X001f 0X0000.016f1c75 0X0180083f 0X00000001 1302762364
.........
index 表示事務表中槽號,只是一個序列而已,從0x00開始到0x21結束,11g的版本有34個槽。
state 表示事務狀態:9代表事務不活動,10代表事務正在活動,從這裡我們看出16進位第0x02號槽上的事務正在活動。
cflags 表示正在使用事務槽的事務的狀態:0x00表示非活動事務、0x80表示活動事務、0x10表示死事務、0x90表示被復原的死事務
wrap# 表示事務表上的事務槽被重用的次數,它是XID的一部分。0x2013表示此時事務槽被重用了8211次。
uel 表示當前活動事務所在事務槽的下一個事務槽的指標(即如果又發生一個新的事務,此時就會用到UEL指向的事務槽上的index)。
scn 表示務事啟動、提交、復原的SCN.
dba 表示uba:第一部分的undo塊地址,這個DBA是(rollback)復原的起始點,也就是說是記錄事務修改的最後一條記錄所在UNDO塊的地址。這使oracle在崩潰恢複時,能夠找到事務產生的最後一條undo記錄,以便知道從何處開始處理復原。
nub 表示當前事務所用到的UNDO塊的個數。交易回復時,可以看到該值會逐步減少。
cmt 表示最接近當前的提交時間戳記,是從1970年1月1號零晨開始的(以秒為單位記錄)。0表示事務正在活動。
2.1 事務的開始和結束
當會話開始一個事務的時候,會先取到一個undo段,從undo段的事務表中取得一條記錄,然後增加該記錄的wrap#的值,將state改為active(10),同時修改事務表其他一些列(比如cmt置0)。由於這也是對於資料庫塊的修改,所以會產生一條最終寫入重做記錄檔的重做改變向量(作業碼為5.2),並寫入資料庫。這樣會話就有了一個活動的事務了。
同樣,當事務完成時(通常是使用者commit),會將state設回為free(9),並更新其他一些列,比如將當期的SCN寫入scn列。同樣,對資料庫塊的這一修改也要產生一個重做改變向量(作業碼5.4),最終記錄到重做日誌中。這一刻相當特別的重要,因為這個時刻你的會話正在向日誌寫進程(lgwr)發布命令將日誌緩衝區的當前內容寫入磁碟,並等待日誌寫進程確認寫入完成,以保護所提交的更改。(這個發送命令要求lgwr進程輸出重做日誌到磁碟其實很簡單,一旦發現進入日誌緩衝區的重做日誌作業碼是5.4,也就是是提交事務記錄,立刻將所有緩衝區的日誌重新整理輸出磁碟,完成後並告知把這條提交記錄放入日誌緩衝區的會話。)
每一個事務會分配一個事務id,事務id由undo段編號,事務表中的條目索引號以及事務條目中最新的wrap#值構成。因此,當你看到像0X0009.002.00002013這樣的事務id時,就會知道:這個事務在undo段9裡,用的是第2條事務表記錄,wrap#值為0X2013。如果你想看這是哪個undo段,以及相應的段頭位置,可以使用segment_id列作為查詢條件查詢dba_rollback_segs視圖。
2.2 事務表
在上面我們已經介紹了事務表的結構了,現在回顧一下,事務表主要的目的無非下面幾個:
1. 顯示事務是已提交還是仍舊活動
2. 已提交事務的SCN
3. 事務產生的最近一條undo記錄的位置資訊,便於復原
4. 事務產生的undo量
如果一個事務必須復原,或者一個會話被強制殺掉,使得smon(系統監視進程)必須要復原它的事務,或者如果執行個體崩潰,在執行個體恢複期間,smon必須復原所有崩潰時的活動事務。那麼此時可以輕鬆找到所有活動事務(狀態等於10),並且找到每一個事務正在使用的最後的undo塊(dba列)。然後可以根據每一個事務對應的undo塊鏈表往回尋找,應用每一條undo記錄,因為每一條undo記錄指向了本事務中前一條undo記錄。
2.3 undo塊簡要介紹
undo塊和普通資料區塊有許多相似之處:塊頭部分記錄了若干控制資訊和中繼資料,行目錄列出了堆積存放在塊中的每一項的位置,若干undo記錄在塊中自底向上堆放在一起,塊空閑空間位於塊中間。但表行和undo記錄最大的區別在於,undo記錄不會被修改,因此一旦undo記錄被寫入塊中,會永遠保留在相同的位置。(表行被修改之後,如果原來位置放不下,會拷貝到另一個新位置,這樣塊中會留下雜亂的指標和臨時的空洞)。
一個不太為人知的事實是,單個undo塊也可以包含多個事務的undo記錄。一個事務會以獨佔的方式請求undo塊的所有權,pin住,然後使用該塊直到塊滿(此時事務請求新undo塊並更新它的事務表槽以指向新塊)或事務提交。如果事務提交後,undo塊中仍有空閑空間,該塊會被加入到undo段頭中空閑塊池的候選鏈表中。如果發生這種情況,該undo塊會被其他事務使用其剩餘的空間。