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