案例(1)
就假設我修改了一條資料:update people set name='Fusnow' where name='old fusnow';
那我需要做的事情包括:
在redo log buffer產生redo資訊(包括對錶的redo,undo的redo,索引什麼的就不考慮了)
在buffer cache裡修改name='Fusnow',修改undo segment
------------------
情況1
如果一切正常,我現在commit,commit會觸發lgwr把redo log buffer裡的資訊寫入到磁碟的redo log file,如果這個操作成功完成,那我的資料安全了,現在如果系統崩潰,儘管可能會丟失buffer cache裡的髒資料,但可以從redo log裡找到重做資訊,所以,可以恢複,當然這個情況不用rollback。
------------------
情況2
如果lgwr把redo log buffer裡的資訊寫入到磁碟的redo log file的過程中系統就崩了,那實際上對使用者而言commit沒有成功就報錯了,這時候datafile和redo log上都沒有我們要的資訊,所以正好,系統啟動的時候我這個改動的roll forward/back 都省了。
------------------
情況3
如果commit之前,有什麼原因導致我們要flush buffer cache,比如buffer cache滿了,oracle要吧buffer cache裡的dirty data寫入到磁碟,這要觸發dbwr,但dbwr寫之前一定要觸發lgwr,先把redo log buffer裡的資料寫入到redo log file。原因很簡單,如果不觸發lgwr,由於對於我的這個改變的髒資料包括表的改動和undo改動,而dbwr很可能不是在一次io裡面把這些髒資料寫入磁碟,如果就是這麼巧,我們先寫入了表的改動,還沒來得及寫undo的髒資料,資料庫崩了,那現在我們的狀態是datafile裡面有改過的表資料,沒有undo資料,redo裡面沒有redo資訊,由於我是沒有commit,所以要復原,但這種情況下是不可能的,因為undo丟了,可以重建undo的redo也丟了。因此,dbwr一定要觸發lgwr。
如果在dbwr觸發lgwr的前提下,我們先寫入了表的改動,還沒來得及寫undo的髒資料的時候資料庫崩了,我們實際上是先roll forward,通過redo產生undo,再rollback,通過undo復原事務。
當然,有兄弟也提過了了,先後順序是1.roll forward, 2.open database, 3.rollback,我想這主要是oracle為了節省時間,因為設計上按照1.roll forward, 2.rollback, 3.open database的順序應該也是可以的,但這樣比較慢,我們完全可以在roll forward結束後馬上open database,然後讓使用者訪問資料庫的其他部分,讓smon慢慢rollback,這時候如果使用者想訪問正被復原的資料是會被堵塞的。當然,在fast模式下,oracle會優先rollback使用者想訪問的block,讓使用者儘快可以訪問這些正被rollback的資料。
案例(2)
假定有一下動作陳述式:
update gaojf set name='exitgogo' where name='old_exitgogo';
這個語句是這樣執行的:
1:首先檢查name='old_exitgogo'是否記錄在buffer cache中,如果不在,讀取到buffer中。
本文URL地址:http://www.bianceng.cn/database/Oracle/201410/45542.htm
2:在復原段資料表空間的相應復原段事務表中分配事務段,這個操作產生redo資訊。
3:從復原段中讀入或者在buffer中或者說是在buffer cache中建立name='old_exitgogo'的前鏡像,這個操作同樣產生redo資訊並記錄寫入redo buffer。
4:在資料緩衝區修改name='exitgogo',這個操作的日誌資訊也寫入redo buffer。
5:當使用者提交時刻,會在redo buffer中記錄提交資訊,同時會在復原段中標記該事務為非啟用狀態(inactive),這點很重要。
可以看到,在一個事務進行過程中,redo和undo是交替出現的,redo buffer會首先記錄此事務變化前的資料和變化後的資料,然後把變化前的資料寫入復原段,最後才在資料緩衝區中修改資料。
以下把instance crash後,先forward,再open,再把未提交的rollback的詳細過程介紹如下:
當以上這個語句執行到第四步的時候,正巧有某種原因導致oracle要flush buffer cache,比如buffer cache滿了等等時間發生,此時,oracle要把髒資料寫入磁碟,也就是此時觸發了dbwr寫進程,又由於dbwr寫之前一定要觸發lgwr,所以以上語句執行的前4步都會寫入redo檔案中。
此時,如果發生資料庫崩潰,由於沒有提交動作發生,也就是沒有第五步的操作了 那麼,在資料庫復原段中標記這個事務將仍為啟用狀態(active)。
在資料庫重新啟動過程中,後台進程SMON會掃描undo segment header,將發現上面的執行語句還是處於啟用狀態,於是, 將這些未提交的活動事務標誌為dead。
roll forward可能發生在以下兩種情況下:
(1):如果以上語句在執行第三步時,資料庫crash,那麼undo復原段中記錄的此事務的前鏡像資料將丟失,資料庫在啟動過程中,會首先發生rollforward,根據redo檔案記錄的資訊,在復原段中產生name='old_exitgogo'的前鏡像。這也是redo為什麼記錄undo資訊的原因。
(2):如果以上語句提交後,dbwr進程還沒有來的及將修改資訊寫到資料檔案,此時資料庫崩了,那麼資料庫在重新啟動後也要進行roll forward,此時根據redo log檔案的記錄更新資料檔案。也就是讓以上語句的更改生效,所以只要提交的資料就不會丟失。
接下來資料庫就可以open。
此後有兩種情況下將發生復原:
(1):後台進程SMON發現dead事務,根據情況去逐步復原。
(2):由於資料庫已經open,可能就有很多使用者進程訪問這些dead事務塊。此時這些前台的進程將會去undo segment取得前鏡像的資料,例如以上的name='old_exitgogo'這個值,然後修改資料緩衝區,完成復原。這個過程本身也要產生redo,因此回退這個操作代價很大。
至此,資料庫啟動過程的前滾以及後援動作完成.