數(shù)據(jù)庫一致性
?
?
??? 一直在將保證數(shù)據(jù)庫的一致性,但是到底什么是一致性,一般的DBMS如何保證數(shù)據(jù)庫的一致性的?對這個問題一直都沒有一個很直觀、完整的認(rèn)識,所以專門研究了一下數(shù)據(jù)庫的一致性問題,學(xué)習(xí)的結(jié)果如下:
?
??? 首先摘一段在百度百科上對于“數(shù)據(jù)庫一致性”的描述:
?
??? 數(shù)據(jù)庫一致性(Database Consistency)是指事務(wù)執(zhí)行的結(jié)果必須是使數(shù)據(jù)庫從一個一致性狀態(tài)變到另一個一致性狀態(tài)。
??? 保證數(shù)據(jù)庫一致性是指當(dāng)事務(wù)完成時(shí),必須使所有數(shù)據(jù)都具有一致的狀態(tài)。在關(guān)系型數(shù)據(jù)庫中,所有的規(guī)則必須應(yīng)用到事務(wù)的修改上,以便維護(hù)所有數(shù)據(jù)的完整性。
??? 保證數(shù)據(jù)庫的一致性是數(shù)據(jù)庫管理系統(tǒng)的一項(xiàng)功能.比如有兩個表(員工/職位),員工表中有員工代碼、姓名、職位代碼等屬性,職位表中有職位代碼、職位名稱、職位等級等屬性。你在其中員工表中進(jìn)行了插入操作,你插入了一個新員工的信息,而這個新員工的職位是公司新創(chuàng)建的一個職位。如果沒有一致性的保證,就會出現(xiàn)有這么一個員工,但是不知道他到底擔(dān)當(dāng)什么職責(zé)!這個只是它的一個小小方面。?
??? 讀一致性也是數(shù)據(jù)庫一致性的一個重要方面,在實(shí)際中,我們會遇到這種情況:我們對一個表中的某些數(shù)據(jù)進(jìn)行了更新操作,但是還沒有進(jìn)行提交,這時(shí)另外一個用戶讀取表中數(shù)據(jù)。這個時(shí)候就出現(xiàn)了讀一致性的問題:到底是讀什么時(shí)候的數(shù)據(jù)呢?是更新前的還是更新后的?在DBMS中設(shè)有臨時(shí)表,它用來保存修改前的值,在沒有進(jìn)行提交前讀取數(shù)據(jù),會讀取臨時(shí)表中的數(shù)據(jù),這樣一來就保證了數(shù)據(jù)是一致的。(當(dāng)前用戶看到的是更新后的值)
??? 但是還有一種情況:用戶user1對表進(jìn)行了更新操作,用戶user2在user1還沒有進(jìn)行提交前讀表中數(shù)據(jù),而且是大批量的讀取(打個比方:耗時(shí)3分鐘)而在這3分鐘內(nèi)user1進(jìn)行了提交操作,那又會產(chǎn)生什么影響呢?這個時(shí)候怎么保證讀寫一致性呢?這個時(shí)候DBMS就要保證有足夠大的臨時(shí)表來存放修改前的數(shù)值,以保證user2讀取的數(shù)據(jù)是修改前的一致數(shù)據(jù)。然后下次再讀取時(shí)候就是更新后的數(shù)據(jù)了。
?
?
??? 個人認(rèn)為:從邏輯上來說:當(dāng)數(shù)據(jù)庫存在沒有結(jié)束的事務(wù)時(shí),數(shù)據(jù)庫就是不一致的。所以要保持?jǐn)?shù)據(jù)庫的一致性,就是要確保某一時(shí)刻沒有事務(wù)在數(shù)據(jù)庫上執(zhí)行即可。例如一般說的數(shù)據(jù)庫一致性備份,就需要在數(shù)據(jù)庫關(guān)閉之后再進(jìn)行。當(dāng)然從物理存儲結(jié)構(gòu)考慮一致性的問題會比較復(fù)雜一些,因?yàn)樯婕暗胶芏辔募男薷牡葐栴},例如Oracle中的各類SCN的設(shè)置。總的來說,可以簡單得認(rèn)為:所有事務(wù)結(jié)束后數(shù)據(jù)庫就是一致的。
?
??? 所以說:數(shù)據(jù)庫的一致性的前提是首先要保證事務(wù)的一致性。事務(wù)的一致性則需要通過并發(fā)控制、鎖、隔離性等限制進(jìn)行保證,具體工作機(jī)制可以參見前文,這里就不再研究了。
?
?
?
Oracle的SCN相關(guān)問題
?
?
??? 下面摘錄一些Oracle控制一致性的方法,來直觀得了解一下,DBMS是如何來處理一致性的問題的:
?
1、SCN的介紹
??? Oracle中的SCN有下面幾種:
?
??? ①系統(tǒng)檢查點(diǎn)scn(v$database(checkpoint_change#))
??????? 當(dāng)一個檢查點(diǎn)動作完成之后,Oracle就把系統(tǒng)檢查點(diǎn)的SCN存儲到控制文件中
??????? select checkpoint_change# from v$database;
??? ②
數(shù)據(jù)文件檢查點(diǎn)scn (v$datafile(checkpoint_change#))
??????? 當(dāng)一個檢查點(diǎn)動作完成之后,Oracle就把每個數(shù)據(jù)文件的scn單獨(dú)存放在控制文件中
??????? select name,checkpoint_change# from v$datafile;
??? ③
數(shù)據(jù)文件終止scn (v$datafile(last_change#))
??????? 每個數(shù)據(jù)文件的終止scn都存儲在控制文件中。在正常的數(shù)據(jù)庫操作過程中,所有正處于聯(lián)機(jī)讀寫模式下的數(shù)據(jù)文件的終止scn都為null
??????? select name,last_change# from v$datafile;
??? ④數(shù)據(jù)文件啟動scn (v$datafile_header(checkpoint_change#)
??????? Oracle把這個檢查點(diǎn)的scn存儲在每個數(shù)據(jù)文件的文件頭中,這個值稱為啟動scn,因?yàn)樗糜谠跀?shù)據(jù)庫實(shí)例啟動時(shí),檢查是否需要執(zhí)行數(shù)據(jù)庫恢復(fù)
??????? select name,checkpoint_change# from v$datafile_header;
2、SCN的工作機(jī)制:
?
??? ①在數(shù)據(jù)庫打開并運(yùn)行之后,控制文件中的系統(tǒng)檢查點(diǎn)scn、控制文件中的數(shù)據(jù)文件檢查點(diǎn)scn和每個數(shù)據(jù)文件頭中的啟動scn都是相同的
?
??? ②控制文件中的每個數(shù)據(jù)文件的終止scn都為null
?
??? ③NORMAL或IMMEDIATE
關(guān)閉數(shù)據(jù)庫的過程中,系統(tǒng)會執(zhí)行一個檢查點(diǎn)動作,這時(shí)所有數(shù)據(jù)文件的終止scn
都會設(shè)置成數(shù)據(jù)文件頭中的那個啟動scn的值。
?
??? ④在數(shù)據(jù)庫重新啟動的時(shí),Oracle將執(zhí)行兩次檢查
??????? ◆ 看數(shù)據(jù)文件頭中的ckpt計(jì)數(shù)器是否與對應(yīng)控制文件中的ckpt計(jì)數(shù)器一致。若相等,進(jìn)行第二次檢查
??????? ◆ 比較文件頭中的啟動scn和對應(yīng)控制文件中的終止scn進(jìn)行比較,如果終止scn等于啟動scn,則不需要對那個文件進(jìn)行恢復(fù)
?
??? ⑤數(shù)據(jù)庫打開之后,存儲在控制文件中的數(shù)據(jù)文件終止scn的值再次被更改為null,這表示數(shù)據(jù)文件已經(jīng)打開并能夠正常使用了
?
??? 注:當(dāng)ABORT強(qiáng)制關(guān)閉數(shù)據(jù)庫時(shí)不進(jìn)行檢查點(diǎn)處理,所以終止scn仍然為無窮大。在下次啟動期間,發(fā)現(xiàn)啟動scn和終止scn不同,需要進(jìn)行線程恢復(fù)。
?
3、SCN的增加
?
??? ①SCN(System Change Number)只要數(shù)據(jù)庫被修改,就會+1,而不是一定要進(jìn)行checkpoint,例如DML的發(fā)生即使沒有提交也會使SCN+1
?
??? 注:SCN增加并不代表會在數(shù)據(jù)文件頭中表現(xiàn)出來,而是需要等到checkpoint執(zhí)行后才寫入(當(dāng)然可能已經(jīng)增加了很多)
?
??? ②如果一個DML導(dǎo)致產(chǎn)生事務(wù),則會產(chǎn)生一個SCN。這個意思是說如果一個事務(wù)包含多個dml,則只有第一個初始產(chǎn)生事務(wù)的dml產(chǎn)生scn,提交的時(shí)候又是一個scn,如果一個事務(wù)只有一個dml,拿看起來就是dml產(chǎn)生一個scn,提交或者回滾產(chǎn)生一個scn。
?
??? ③Oracle 10g內(nèi)部的SCN會默認(rèn)不管有沒有動作,每隔3s自動增加一次。其他需要增加的情況則再加。
?
??? ④只有ckpt進(jìn)程才會修改文件頭中的checkpoint計(jì)數(shù)器和SCN,DBWR只會修改數(shù)據(jù)塊,即ckpt通知dbwr寫數(shù)據(jù)文件,寫完之后ckpt更新控制文件和數(shù)據(jù)文件頭。此時(shí)若DBWR發(fā)現(xiàn)數(shù)據(jù)塊的log block還沒有被寫入日志文件,則在dbwr寫塊之前通知llgwr把log buffer中的日志寫入log文件。
?
??? 注:總結(jié)一下,日志切換必定出發(fā)ckpt,但ckpt不一定會出發(fā)llgwr,但是一定會觸發(fā)dbwr
?
?
4、其他的SCN
?
??? ①日志文件頭中包含了Low scn、Next scn,表示給日志文件包含有從Low scn到Next scn的redo record
?
???
注:當(dāng)系統(tǒng)運(yùn)行時(shí),日志文件的Next scn同樣為無窮大。而且需要注意:在恢復(fù)時(shí)不是用日志文件中的Low scn和Next scn來選擇恢復(fù)的日志文件,而是通過數(shù)據(jù)文件頭中的信息。
?
??? ②數(shù)據(jù)塊中的SCN
??? data?block里面的SCN是當(dāng)block被更改的時(shí)候的SCN,而數(shù)據(jù)文件有那么多 block,自然不同的block有不同的SCN,block中存在block?SCN和ITL中的commit SCN。block SCN 又在塊頭和塊位都有,若不一致意味著block損壞。而ITL中的commit?SCN則跟consistent gets?and?delay?block?cleanout有關(guān)。
??? ③v$database中的checkpoint_change# 和 dbms_flashback.get_system_change_number 不同。前者是作為數(shù)據(jù)庫的最后一次checkpoint是的SCN,而后者是系統(tǒng)的最新SCN,所以一般后者都會比前者大,而當(dāng)剛做完checkpoint時(shí)兩者會差不多。
?
??? ④當(dāng)begin backup命令發(fā)出后,相關(guān)數(shù)據(jù)文件的checkpoint scn被凍結(jié)(以及狀態(tài)標(biāo)志被改變),其他一切照舊。例如:日志切換時(shí)checkpoint count正常遞增/檢查點(diǎn)照常寫文件,自然文件中的數(shù)據(jù)塊內(nèi)的各種scn也照常遞增。
?
?
?
?
?
說明:以上內(nèi)容均來自IPPUB論壇的一貼討論,來來回回看了好幾遍,又自己實(shí)踐了一下才稍微對Oracle的SCN有了一點(diǎn)了解。有時(shí)間要學(xué)習(xí)一下理論知識。
?
?
-The End-