Oracle還是比較常用的,於是我研究了一下Oracle COMMIT,在這裡拿出來和大家分享一下,希望對大家有用。只有當SQL語句影響的所有行所在的最後一個塊被讀入DB BUFFER並且重做信息被寫入REDO LOG BUFFER之後,用戶才可以發出COMMIT,Oracle COMMIT觸發LGRW,但並不強制立即DBWN來釋放所有相應的DB BUFFER塊上的鎖,但在隨後的一段時間內DBWN還在寫這條語句涉及的數據塊的情形,表頭部的行鎖,並不是在COMMIT一發出就馬上釋放,實際上要等到相應的DBWN進程結束才會釋放。
一個用戶請求鎖定另一個用戶已COMMIT的資源不成功的機會是存在的。Oracle COMMIT發出後會將回滾段中的"前映像"標識為已提交.DML語句會產生一個SCN號,DBWN觸發時寫入到數據塊的頭部,COMMIT時也會產生一個SCN號,也會被寫入數據塊的頭部。在數據塊的頭部只存儲一個最新的SCN號,COMMIT之後這個事務插槽可以被另外一個事務使用。如果用戶ROOLBACK,則服務器進程會根據數據文件塊和DB BUFFER中塊的頭部的事務列表和SCN以及回滾段地址重構出相應的修改前的副本,並且用這些原值來還原當前數據文件中已修改但未提交的改變。如果有多個"前映像",服務器進程會在一個"前映像"的頭部找到"前前映像"的回滾段地址,一直重構出同一事務下的最早的一個"前映像"為止。一旦發出了COMMIT,用戶就不能ROLLBACK,這使得COMMIT後DBWN進程還沒有全部完成的後續動作得到了保障。
下面我們要提到檢查點的作用,ckpt的觸發,有以下幾種情況:
1.當發生日志組切換的時候
2.當滿足log_checkpoint_timeout、log_checkpoint_interval、fast_start_io_target、fast_start_mttr_target參數設置的時候
3.當運行alter system switchlogfile的時候
4.當運行alter systemckeckpoint的時候
5.當運行altertablespacetbs_namebegin backup[end backup]的時候
6.當運行altertablespace[datafile] offline的時候
7.系統正常關閉時
只有在4.7兩種情況下發生完全檢查點。發生完全檢查點時,首先系統記錄檢查點對應的Checkpoint SCN,並記錄下該時刻修改的DB BUFFER對應的日志文件的最新的重做字節地址(Redo Byte Address (RBA)),然後DBWN進程將這個重做字節地址(RBA)之前已發生的DB BUFFER中的髒緩沖寫入數據文件(之所以要以重做字節地址(RBA)為標志是因為在檢查點發生到檢查點完成之間的時間內,系統還在一直不斷的產生修改,這些修改所產生的DB BUFFER髒緩沖,以及日志條目將不會影響這次檢查點最後確認的一致性結果,也就是最後確認這個Checkpoint SCN之前的系統是一致的)。
最後把Checkpoint SCN和RBA更新至控制文件,Checkpoint SCN更新至每個數據文件頭部,表明當前數據庫是一致的。日志切換並不導致一個完全檢點的發生,比如有三個日志文件組,當發生日志切換時發生檢查點,而發生日志切換一般是因為當前的LGWR正在寫重做日志,也就是LGWR當剛寫滿2號日志就立即觸發檢查點,於是系統開始核對3號日志中記錄的REDO項目所對應的數據是否已經從DB BUFFER中寫入數據文件(不管事務是否已提交),如果沒有寫入,檢查點就觸發DBWN進程將這些緩沖塊寫入數據文件,顯然LGWR因此而發生等待,除此以外,檢查點還讓DBWN進程將在2號日志中對應修改的DB BUFFER塊寫入數據文件,然後繼續LGWR進程,直到LGWR進程將LGWR觸發之前存在於REDO LOG BUFFER中的所有緩沖(包含未提交的重做信息)寫入重做日志文件,檢查點再更新數據文件,控制文件頭部SCN。其實LGWR等待的並不是CKPT的完成,而是等待CKPT觸發的DBWN進程的完成。
可以想像斷電時可能既有未COMMIT的事務,也可能同時存在已COMMIT但DBWN未完成的情況,如果斷電時有一個已COMMIT但DBWN動作沒有完成的情況存在,因為已經COMMIT,COMMIT會觸發LGWR進程,所以不管DBWN動作是否已完成,該語句將要影響的行及其產生的結果一定已經記錄在重做日志文件中了,則實例重啟後,SMON進程從控制文件中記錄的上一次重做字節地址(RBA)開始,按照重做日志文件中的條目對數據文件和回滾段重新做一遍即前滾,注意這些條目的操作在斷電之前有的已經被DBWN寫入了數據文件,有的還沒有來得及寫,不管有沒有寫進數據文件,前滾時都會再重新寫一次(9I之前是這樣的),9I之後,由於也在日志中記錄了DBWN改寫的塊信息,系統會過濾掉已寫入的條目而只重做那些未寫入的條目。對於一個未提交事務,分幾種情況來描述:
1)LGWR與DBWN一致的情況即一個語句執行完成後很長時間也沒有COMMIT,這種情況一般不存在DBWN來不及完成的情況。只是沒有Oracle COMMIT而已。那麼SMON將在前滾完成後,利用回滾段重構出具有最小SCN的前映像,並把它的值寫回原位。
2)事務執行中斷電,即可能存在LGWR與DBWN不同步的情況(因為DBWN之前會觸發LGWR,所以DBWN對數據文件的修改一定會被先記錄在重做日志文件中。因此只可能存在已寫入重做日志而未來得及寫入數據文件的情況存在。而不可能存在已寫入數據文件卻沒有寫入日志文件的情況。),這種情況下SMON也會先前滾一點(即把數據文件與相應的日志文件先同步再回滾,之所以說前滾一點,是指僅LGWR與DBWN之間進度的差距,而不是把這條語句進行到底再回滾,因為日志文件中記錄的是執行語句操作的一個個塊的修改信息,而不只是記錄一條執行語句的字面內容),然後利用回滾段重構出具有最小SCN的前映像,並把它的值寫回原位。由此可見,實例失敗後用於恢復的時間由兩個檢查點之間的間隔大小來決定,我們可以通個四個參數設置檢查點執行的頻率,LOG_CHECKPOINT_IMTERVAL決定了兩個檢查點之間寫入重做日志文件的系統物理塊的大小,LOG_CHECKPOINT_TIMEOUT決定了兩個檢查點之間的時間長度,FAST_START_IO_TARGET決定了用於恢復時需要處理的塊的大小,FAST_START_MTTR_TARGET直接決定了用於恢復的時間的長短。
檢查點的作用就是不斷的確認LGWR與DBWN之間的同步情況,以便實例失敗後從上一個檢查點開始恢復,問題是兩個檢查點之間LGWR與DBWN大部分的操作是同步的,只是一小部分沒有同步,這種傳統的檢查點使實例恢復做了比較多的無用功,因此,ORACLE引入了增量檢查點,增量檢查點會在上一次傳統檢查點發生後到下一次傳統檢查點發生之前,不斷的更新記錄在控制文件中重做字節地址(RBA)(CKPT進程每三秒更新一次,見下面DBWN講述),這樣實例失敗後將直接從控制文件中記錄的最後更新的重做字節地址(RBA)開始進行前滾和回滾,這就省略掉了恢復時大部份的重做日志的重做(即使在9I以後的版本裡也省略掉了大部分的過濾重做日志條目的時間)。(對以上描述做一個簡單的比喻:比如一個貿易公司下設經營部、貨運部、監督部,經營部負責貿易合同的簽訂與記錄,貨運部負責按合同號的順序把貨物送達,監督部負責定期檢查確認經營部簽訂的合同與貨運部貨物送達情況之間的同步情況,監督部每月檢查一次,每次檢查時,先確認當時正在裝車的貨物的合同號,並要求貨運部把在這個合同號之前的所有還存在臨時倉庫中的未送貨物全部送達。等貨運部完成監督部下達的任務後,監督部在檢查本上記錄下本次開始檢查時那票正在裝車的貨物的合同號,本次檢查完成。如果這個公司發生了一次人事大換血,公司重新開業後,監督部就會從檢查本上記錄的合同號開始,檢查在這之後所有發生的合同及貨物送達情況,要求貨運部把所有客戶確認的但還未送達的貨物送達。以上介紹Oracle COMMIT。