深入瞭解SCN
SCN: System Change Number
SCN是順序遞增的一個數字,在Oracle 中用來標識資料庫的每一次改動,及其先後順序。SCN的最大值是0xffff.ffffffff。
Oracle對SCN的管理
單節點的Instance中
單節點的instance中,SCN值存在SGA區,由system commit number latch保護。任何程式要得到當前的SCN值,都要先得到這個latch。
RAC/OPS環境中
Oracle通過排隊機制(Enqueue)實現SCN在各並行節點之間的順序增長。具體有兩種方法:
Lamport演算法:又稱麵包房演算法,先來先服務演算法。跟很多銀行採用的排隊機制一樣。客戶到了銀行,先領取一個服務號。一旦某個視窗出現空閒,擁有最小服務號的客戶就可以去空閒視窗辦理業務。
Commit廣播演算法:一有commit完成,最新的SCN就廣播到所有節點中。
上述兩種演算法可以通過調整初始化引數max_commit_propagation_delay來切換。在多數系統 (除了Compaq Tur64 Unix)中,該引數的預設值都是700釐秒(centisecond),採用Lamport演算法。如果該值小於100釐秒,Oracle就採用廣播演算法,並且記錄在alert.log檔案中。
幾種重要的SCN
Commit SCN
當使用者提交commit命令後,系統將當前scn賦給該transaction。這些資訊都反映在redo buffer中,並馬上更新到redo log 檔案裡。
Offline SCN
除了System tablespace以外的任何表空間,當我們執行SQL>alter tablespace … offline normal命令時,就會觸發一個checkpoint,將記憶體中的dirty buffer寫入磁碟檔案中。Checkpoint完成後,資料檔案頭會更新checkpoint scn和offline normal scn值。其中資料庫檔案頭的checkpoint scn值可通過查詢列x$kccfe.fecps得到。
如果執行SQL>alter tablespace …offline命令時採用temporary或 immediate選項,而不用normal選項時,offline normal scn會被設成0。這樣當資料庫重啟後通過resetlog方式開啟時,該表空間就無法再改回線上狀態。
Checkpoint SCN
當資料庫記憶體的髒資料塊(dirty blocks)寫到各資料檔案中時,就發生一次checkpoint。資料庫的當前checkpoint scn值存在x$kccdi.discn中。Checkpoint scn在資料庫恢復中起著至關重要的作用。無論你用何種辦法恢復資料庫,只有當各個資料庫檔案的checkpoint scn都相同時,資料庫才能開啟。
雖然引數“_allow_resetlogs_corruption”可以在checkpoint scn不一致時強制開啟資料庫,但是這樣的資料庫在open後必須馬上作全庫的export,然後重建資料庫並import資料。
Resetlog SCN
資料庫不完全恢復時,在指定時間點後的scn都無法再應用到資料庫中。Resetlog時的scn就被設成當前資料庫scn,redo log也會被重新設定。
Stop SCN
Stop scn記錄在資料檔案頭上。當資料庫處在開啟狀態時,stop scn被設成最大值0xffff.ffffffff。在資料庫正常關閉過程中,stop scn被設定成當前系統的最大scn值。在資料庫開啟過程中,Oracle會比較各檔案的stop scn和checkpoint scn,如果值不一致,表明資料庫先前沒有正常關閉,需要做恢復。
High and Low SCN
Oracle的Redo log會順序紀錄資料庫的各個變化。一組redo log檔案寫滿後,會自動切換到下一組redo log檔案。則上一組redo log的high scn就是下一組redo log的low scn。
在檢視v$log_history中,sequence#代表redo log的序列號,first_change#表示當前redo log的low scn,列next_change#表示當前redo log的high scn。
SQL> col recid format 9999
SQL> col requence# format 9999
SQL> col first_change# format 9,999,999,999,999
SQL> col next_change# format 9,999,999,999,999
SQL> select recid,sequence#,first_change#,next_change# from v$log_history where rownum<6;
RECID SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#
----- ---------- ------------------ ------------------
484 484 1,928,645,840,091 1,928,645,840,436
485 485 1,928,645,840,436 1,928,645,840,636
486 486 1,928,645,840,636 1,928,778,045,209
487 487 1,928,778,045,209 1,929,255,480,725
488 488 1,929,255,480,725 1,930,752,214,033
關於如何使用引數_allow_resetlogs_corruption,可參見文件http://www.sidibe.net/allow_resetlog.html