ORACLE寫日誌過程存在缺陷

wei-xh發表於2012-03-07

CODE:

Session 1


create table t1(n1 number);
insert into t1 values(1);
commit;

session 2 (sysdba)


oradebug setorapid 12(LGWR的程式)
oradebug suspend

session 1


update t1 set n1 = 2;
commit; 會話被hang住了

session 3


select n1 from smart.t1;

N1
----------
2很驚奇,我們看到的是2.commit在發出後,ORACLE需要做塊清除,UNDO段頭的塊清除,資料塊的塊清除,但是資料塊的清除一般是延遲塊清除。而UNDO塊頭無論如何,是要清除的,就像我們知道的,需要把UNDO段頭的事務槽的事務活動狀態修改為9,修改提交SCN等。這些清除也是要產生REDO的,這些REDO會隨著事務的日誌重新整理LOG BUFFER裡。這些日誌被重新整理到LOG BUFFER後,由於LGWR被我們掛起來了,導致寫不到LOGFILE裡。可是無論如何回滾段頭的事務槽已經做了清除,代表事務已經終結。這個時候,一個讀程式讀取資料塊,雖然很大可能由於延遲塊清除導致資料塊的事務資訊沒被清理,可是在參照回滾段頭後,發現這個事務已經提交了。雖然這個提交沒被持久化進LOGFILE裡。在某些情況下,比如空間不足,導致切換日誌切換不下去,或者在做日誌切換時候,切換比較久,就可能會導致產生這種不一致的讀。   我們重啟例項後,再看。

CODE:

session 3 select n1 from smart.t1;
N1
----------
1ORACLE已經對上面的事務成功回滾了 ORACLE為什麼能在這個情況下進行回滾呢?同事提出了一個問題,如果這個時候UNDO段頭對應的髒快已經被刷入到磁碟了怎麼辦?我們知道前滾的時候,是需要在舊的資料塊上應用新日誌來達到目的,但是萬一髒資料塊已經被重新整理到了磁碟,也就是事務提交資訊已經被寫入到了磁碟,由於日誌沒被寫進LOG FILE,那麼這個事務其實是沒法回滾了。LEWIS告訴了我們答案:One of the most important features of the Oracle code is that the database writer will not write a
changed block to disk before the log writer has written the redo that describes how the block was changed.
也就是說,日誌不寫入LOG FILE,對應的髒快是不會提前寫進去。   

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

相關文章