天天看點

Oracle_Oracle前滾/Oracle後滾

案例(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中。

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,是以回退這個操作代價很大。

至此,資料庫啟動過程的前滾以及回退操作完成.

oracle視訊教程請關注:http://u.youku.com/user_video/id_umzazmjkxmje2.html