數據庫一致性研究【Oracle SCN】

數據庫一致性
    一直在將保證數據庫的一致性,但是到底什麼是一致性,一般的DBMS如何保證數據庫的一致性的?對這個問題一直都沒有一個很直觀、完整的認識,所以專門研究了一下數據庫的一致性問題,學習的結果如下:
    首先摘一段在百度百科上對於“數據庫一致性”的描述:
   數據庫一致性(Database Consistency)是指事務執行的結果必須是使數據庫從一個一致性狀態變到另一個一致性狀態。
   保證數據庫一致性是指當事務完成時,必須使所有數據都具有一致的狀態。在關係型數據庫中,所有的規則必須應用到事務的修改上,以便維護所有數據的完整性。
    保證數據庫的一致性是數據庫管理系統的一項功能.比如有兩個表(員工/職位),員工表中有員工代碼、姓名、職位代碼等屬性,職位表中有職位代碼、職位名稱、職位等級等屬性。你在其中員工表中進行了插入操作,你插入了一個新員工的信息,而這個新員工的職位是公司新創建的一個職位。如果沒有一致性的保證,就會出現有這麼一個員工,但是不知道他到底擔當什麼職責!這個只是它的一個小小方面。
    讀一致性也是數據庫一致性的一個重要方面,在實際中,我們會遇到這種情況:我們對一個表中的某些數據進行了更新操作,但是還沒有進行提交,這時另外一個用戶讀取表中數據。這個時候就出現了讀一致性的問題:到底是讀什麼時候的數據呢?是更新前的還是更新後的?在DBMS中設有臨時表,它用來保存修改前的值,在沒有進行提交前讀取數據,會讀取臨時表中的數據,這樣一來就保證了數據是一致的。(當前用戶看到的是更新後的值)
    但是還有一種情況:用戶user1對錶進行了更新操作,用戶user2在user1還沒有進行提交前讀表中數據,而且是大批量的讀取(打個比方:耗時3分鐘)而在這3分鐘內user1進行了提交操作,那又會產生什麼影響呢?這個時候怎麼保證讀寫一致性呢?這個時候DBMS就要保證有足夠大的臨時表來存放修改前的數值,以保證user2讀取的數據是修改前的一致數據。然後下次再讀取時候就是更新後的數據了。
    個人認爲:從邏輯上來說:當數據庫存在沒有結束的事務時,數據庫就是不一致的。所以要保持數據庫的一致性,就是要確保某一時刻沒有事務在數據庫上執行即可。例如一般說的數據庫一致性備份,就需要在數據庫關閉之後再進行。當然從物理存儲結構考慮一致性的問題會比較複雜一些,因爲涉及到很多文件的修改等問題,例如Oracle中的各類SCN的設置。總的來說,可以簡單得認爲:所有事務結束後數據庫就是一致的。
    所以說:數據庫的一致性的前提是首先要保證事務的一致性。事務的一致性則需要通過併發控制、鎖、隔離性等限制進行保證,具體工作機制可以參見前文,這裏就不再研究了。
Oracle的SCN相關問題
    下面摘錄一些Oracle控制一致性的方法,來直觀得了解一下,DBMS是如何來處理一致性的問題的:
1、SCN的介紹

    Oracle中的SCN有下面幾種:
    ①系統檢查點scn(v$database(checkpoint_change#))
        當一個檢查點動作完成之後,Oracle就把系統檢查點的SCN存儲到控制文件中
        select checkpoint_change# from v$database;
    數據文件檢查點scn (v$datafile(checkpoint_change#))
        當一個檢查點動作完成之後,Oracle就把每個數據文件的scn單獨存放在控制文件
        select name,checkpoint_change# from v$datafile;
    數據文件終止scn (v$datafile(last_change#))
        每個數據文件的終止scn都存儲在控制文件中。在正常的數據庫操作過程中,所有正處於聯機讀寫模式下的數據文件的終止scn都爲null
        select name,last_change# from v$datafile;
    ④數據文件啓動scn (v$datafile_header(checkpoint_change#)
        Oracle把這個檢查點的scn存儲在每個數據文件的文件頭中,這個值稱爲啓動scn,因爲它用於在數據庫實例啓動時,檢查是否需要執行數據庫恢復
        select name,checkpoint_change# from v$datafile_header;
2、SCN的工作機制:
    ①在數據庫打開並運行之後,控制文件中的系統檢查點scn、控制文件中的數據文件檢查點scn和每個數據文件頭中的啓動scn都是相同的
   ②控制文件中的每個數據文件的終止scn都爲null
   ③NORMAL或IMMEDIATE關閉數據庫的過程中,系統會執行一個檢查點動作,這時所有數據文件的終止scn都會設置成數據文件頭中的那個啓動scn的值。
    ④在數據庫重新啓動的時,Oracle將執行兩次檢查
        ◆ 看數據文件頭中的ckpt計數器是否與對應控制文件中的ckpt計數器一致。若相等,進行第二次檢查
        ◆ 比較文件頭中的啓動scn和對應控制文件中的終止scn進行比較,如果終止scn等於啓動scn,則不需要對那個文件進行恢復
    ⑤數據庫打開之後,存儲在控制文件中的數據文件終止scn的值再次被更改爲null,這表示數據文件已經打開並能夠正常使用了
    注:當ABORT強制關閉數據庫時不進行檢查點處理,所以終止scn仍然爲無窮大。在下次啓動期間,發現啓動scn和終止scn不同,需要進行線程恢復。
3、SCN的增加
    ①SCN(System Change Number)只要數據庫被修改,就會+1,而不是一定要進行checkpoint,例如DML的發生即使沒有提交也會使SCN+1
    注:SCN增加並不代表會在數據文件頭中表現出來,而是需要等到checkpoint執行後才寫入(當然可能已經增加了很多)
   ②如果一個DML導致產生事務,則會產生一個SCN。這個意思是說如果一個事務包含多個dml,則只有第一個初始產生事務的dml產生scn,提交的時候又是一個scn,如果一個事務只有一個dml,拿看起來就是dml產生一個scn,提交或者回滾產生一個scn。
    ③Oracle 10g內部的SCN會默認不管有沒有動作,每隔3s自動增加一次。其他需要增加的情況則再加。
    ④只有ckpt進程纔會修改文件頭中的checkpoint計數器和SCN,DBWR只會修改數據塊,即ckpt通知dbwr寫數據文件,寫完之後ckpt更新控制文件和數據文件頭。此時若DBWR發現數據塊的log block還沒有被寫入日誌文件,則在dbwr寫塊之前通知llgwr把log buffer中的日誌寫入log文件。
    注:總結一下,日誌切換必定出發ckpt,但ckpt不一定會出發llgwr,但是一定會觸發dbwr
4、其他的SCN
    ①日誌文件頭中包含了Low scn、Next scn,表示給日誌文件包含有從Low scn到Next scn的redo record
   注:當系統運行時,日誌文件的Next scn同樣爲無窮大。而且需要注意:在恢復時不是用日誌文件中的Low scn和Next scn來選擇恢復的日誌文件,而是通過數據文件頭中的信息。
   ②數據塊中的SCN
    data block裏面的SCN是當block被更改的時候的SCN,而數據文件有那麼多 block,自然不同的block有不同的SCN,block中存在block SCN和ITL中的commit SCN。block SCN 又在塊頭和塊位都有,若不一致意味着block損壞。而ITL中的commit SCN則跟consistent gets and delay block cleanout有關。
    ③v$database中的checkpoint_change# 和 dbms_flashback.get_system_change_number 不同。前者是作爲數據庫的最後一次checkpoint是的SCN,而後者是系統的最新SCN,所以一般後者都會比前者大,而當剛做完checkpoint時兩者會差不多。
    ④當begin backup命令發出後,相關數據文件的checkpoint scn被凍結(以及狀態標誌被改變),其他一切照舊。例如:日誌切換時checkpoint count正常遞增/檢查點照常寫文件,自然文件中的數據塊內的各種scn也照常遞增。
說明:以上內容均來自IPPUB論壇的一貼討論,來來回回看了好幾遍,又自己實踐了一下才稍微對Oracle的SCN有了一點了解。有時間要學習一下理論知識。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章