oracle scn研究

深入瞭解Oracle SCN (1)

--------------------------------------------------------------------------------


[說明]本來在研究Backup and Recovery,可是在做實驗的時候遇到一些問題不是很理解,進而追根求源,想搞清楚,於是必須搞清楚SCN和Recovery之間的關係。於是乎轉而研究SCN,這兩天看了很多文章,包括Eygle網站上的文章,itpub上biti等大師以前發過或者參與討論過的帖子,發現思路有模糊到清晰,再由清晰到模糊,越走越深,至今還沒有完全搞清楚。決定暫時到此爲止,等以後各方面的知識積累多了,再轉過來研究一下。本想自己寫個總結性的文章,可是發現了一篇文章已經寫的很好了,我就懶惰的以逸待勞,copy過來了,在此謝謝前輩們的工作,大家辛苦了~
SCN的概念
SCN是順序遞增的一個數字,在Oracle中用來標識數據庫的每一次改動,及其先後順序。SCN的最大值是0xffff.ffffffff。
SCN的管理方式
Oracle對SCN的管理,分爲單節點和RAC兩種方式。
單節點的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
 
SCN號與oracle數據庫恢復的關係
SCN號與oracle數據庫恢復過程有着密切的關係,只有很好地理解了這層關係,才能深刻地理解恢復的原理,從而才能很好地解決這方面的問題。
SCN與CHECKPOINT
CKPT進程在checkpoint發生時,將當時的SCN號寫入數據文件頭和控制文件,同時通知DBWR進程將數據塊寫到數據文件。
CKPT進程也會在控制文件中記錄RBA(redo byte address),以標誌Recovery需要從日誌中哪個地方開始。與checkpoint相關的SCN號有四個,其中三個存在控制文件中,一個存放在數據文件頭中。
這四個分別是:
1.System Checkpoint SCN
當checkpoint完成後,ORACLE將System Checkpoint SCN號存放在控制文件中。我們可以通過下面SQL語句查詢:
select checkpoint_change# from v$database;
2.Datafile Checkpoint SCN
當checkpoint完成後,ORACLE將Datafile Checkpoint SCN號存放在控制文件中。我們可以通過下面SQL語句查詢所有數據文件的Datafile Checkpoinnt SCN號。
select name,checkpoint_change# from v$datafile;
3.Start SCN號
ORACLE將Start SCN號存放在數據文件頭中。
這個SCN用於檢查數據庫啓動過程是否需要做Media Recovery.
我們可以通過以下SQL語句查詢:
select name,checkpoint_change# from v$datafile_header;
4.End SCN (Stop SCN)號
ORACLE將End SCN號存放在控制文件中。
這個SCN號用於檢查數據庫啓動過程是否需要做Instance Recovery.
我們可以通過以下SQL語句查詢:
select name,last_change# from v$datafile;
在數據庫正常運行的情況下,對可讀寫的,online的數據文件,該SCN號爲NULL.
我們作個小的試驗,內容如下:
在執行檢查點進程之前SCN號如下:
System Checkpoint SCN 4609061
--select checkpoint_change# from v$database;
Datafile Checkpoint SCN 4609061
--select name,checkpoint_change# from v$datafile;
Start SCN 4609061
--select name,checkpoint_change# from v$datafile_header;
End SCN空
--select name,last_change# from v$datafile;
執行alter system checkpoint。後的SCN號如下:
System Checkpoint SCN 4609630
--select checkpoint_change# from v$database;
Datafile Checkpoint SCN 4609630
--select name,checkpoint_change# from v$datafile;
Start SCN 4609630
--select name,checkpoint_change# from v$datafile_header;
End SCN null
--select name,last_change# from v$datafile;
SCN不連續原因可能如下: 
1.當發生日誌組切換的時候
2.當符合LOG_CHECKPOINT_TIMEOUT,LOG_CHECKPOINT_INTERVAL,fast_start_io_target,fast_start_mttr_target參數設置的時候
3.當運行ALTER SYSTEM SWITCH LOGFILE的時候
4.當運行ALTER SYSTEM CHECKPOINT的時候
5.當運行alter tablespace XXX begin backup,end backup的時候
6.當運行alter tablespace ,datafile offline的時候;
SCN號與數據庫啓動
在數據庫啓動過程中,當System Checkpoint SCN、Datafile Checkpoint SCN和Start SCN號都相同時,數據庫可以正常啓動,不需要做media recovery.三者當中有一個不同時,則需要做media recovery。如果在啓動的過程中,End SCN號爲NULL,則需要做instance recovery。ORACLE在啓動過程中首先檢查是否需要media recovery,然後再檢查是否需要instance recovery。
SCN號與數據庫關閉
如果數據庫的正常關閉的話,將會觸發一個checkpoint,同時將數據文件的END SCN號設置爲相應數據文件的Start SCN號。
當數據庫啓動時,發現它們是一致的,則不需要做instance recovery。在數據庫正常啓動後,ORACLE會將END SCN號設置爲NULL。如果數據庫異常關閉的話,則END SCN號將爲NULL.
爲什麼需要System checkpoint SCN號與Datafile Checkpoint SCN號
爲什麼ORACLE會在控制文件中記錄System checkpoint SCN號的同時,還需要爲每個數據文件記錄
Datafile Checkpoint SCN號?
原因有二:
1.對只讀表空間,其數據文件的Datafile Checkpoint SCN、Start SCN和END SCN號均相同。
這三個SCN在表空間處於只讀期間都將被凍結。
2.如果控制文件不是當前的控制文件,則System checkpoint會小於Start SCN或END SCN號。記錄這些SCN號,可以區分控制文件是否是當前的控制文件。
Recovery database using backup controlfile
當有一個Start SCN號超過了System Checkpoit SCN號時,則說明控制文件不是當前的控制文件,因此在做recovery時需要採用using backup controlfile。這是爲什麼需要記錄SystemCheckpoint SCN的原因之一。
這裏需要一提的是,當重建控制文件的時候,System Checkpoint SCN爲0,Datafile Checkpoint SCN的數據來自於Start SCN。根據上述的描述,此時需要採用using backup controlfile做recovery。
重建控制文件,重建方式分兩種(resetlogs和noresetlogs)(此段內容來自:http://space.51CTO提醒您,請勿濫發廣告!/12361284/viewspace-346)
1.使用resetlogs選項時,System Checkpoint SCN爲被歸爲0,而其中記錄的各個數據文件的Datafile Checkpoint SCN則來自於Start SCN(也就是說可能會從冷備份的數據文件的數據文件頭中獲取)。根據上述的描述,此時需要採用using backup controlfile做recovery.因此情況是System Checkpoint SCN=0 < Start SCN = Datafile Checkpoint SCN。
2.使用noresetlogs選項時,有一個前提就是:一定要有online redo log的存在。否則就要使用resetlogs選項。這個時候控制文件重建好時,其system checkpoint SCN=Datafile Checkpoint SCN=Lastest Checkpoint SCN in online redo log,我們可以看到Datafile Checkpoint SCN並沒有從Start SCN中讀取。而是讀取了最新的日誌文件中的SCN作爲自己的數據。此時重建的控制文件在恢復中的作用跟最新的控制文件類似,System Checkpoint SCN(已經讀取最新的redo log的checkpoint SCN信息)可能會>Start SCN(因爲數據文件可能會從冷備份中恢復),恢復時就不需要加using backup controlfile子句了。
關於backup controlfile的補充:backup controlfile只有備份時刻的archive log信息,並沒有DB crash時刻的archive log信息,所以並不會自動應用online redo log,而是提示找不到序號爲Lastest Archive log sequence + 1的archive log,儘管你可以手動指定online redo log來實現完全恢復,但因爲一旦使用了using backup controlfile子句,Oracle就視爲不完全恢復,必須open resetlogs!實際上,假如你有舊的控制文件又不想resetlogs,那很簡單,使用舊的控制文件mount然後backup to trace,然後手工創建控制文件,使用reuse database ... noresetlogs .這樣就可以recover database自動恢復並open database而不用resetlogs了(記住:必須有所有的online redo logs纔可以這樣!)。
備份的控制文件不能自動進行完全恢復
可以手工apply日誌進行完全恢復
 
重新創建的可以自動進行完全恢復(By biti)
示例
例子背景:
oracle 8i
windows
採用rman做熱備,在備份期間,做不少事務,同時做alter system checkpoint.
RMAN> run {
2> allocate channel c1 type disk;
3> backup database filesperset 3 format 'e:/full_%p_%t.bak';
4> }
(這裏需要一提的是,在這個備份角本里面我們加了filesperset 3。這樣將整個數據庫分成兩個備份集。這樣還原出來的數據文件其checkpoint_change#將不一樣。否則由於數據庫數據文件不多,都將包含在一個備份集中,這樣即使在備份中做insert操作和alter system checkpoint也不會產生不同的checkpoint_change#。因爲rman備份是將一個備份集中的文件同時備份的。
而checkpoint_change#是存放在數據文件頭部的,這樣備份這些數據文件的頭部的時間將是很快的。)
然後
RMAN> run{
2> allocate channel c1 type disk;
3> restore database;
4> }

SQL> select checkpoint_change# from v$database;
CHECKPOINT_CHANGE#
------------------
2156662354
SQL> select file#,checkpoint_change# from v$datafile;
FILE# CHECKPOINT_CHANGE#
---------- ------------------
1 2156662355
2 2156662354
3 2156662322
4 2156662354
5 2156662354
6 2156662354
SQL> select file#,checkpoint_change# from v$datafile_header;
FILE# CHECKPOINT_CHANGE# LAST_CHANGE#
---------- ------------------ -------------
1 2156662355
2 2156662349
3 2156662322
4 2156662342
5 2156662349
6 2156662342
從這裏可以看出,顯然是需要做media recovery的。正常情況下,還需要做instance recovery.當然由於沒有在線日誌,所以只能做resetlogs。
1.有歸檔日誌存
若有歸檔日誌在,則只需要做一個recover database until cancel;
然後即可alter database open resetlogs;

SQL> recover database until cancel (using backup controlfile);
ORA-00279: change 2156621770 generated at 10/07/2005 14:30:06 needed for thread 1
ORA-00289: suggestion : D:ORACLE8IRDBMSARC00738.001
ORA-00280: change 2156621770 for thread 1 is in sequence #738

Specify log: {=suggested | filename | AUTO | CANCEL}
auto
ORA-00279: change 2156621779 generated at 10/07/2005 14:30:51 needed for thread
1
ORA-00289: suggestion : D:ORACLE8IRDBMSARC00739.001
ORA-00280: change 2156621779 for thread 1 is in sequence #739
ORA-00278: log file 'D:ORACLE8IRDBMSARC00738.001' no longer needed for this recovery

ORA-00308: cannot open archived log 'D:ORACLE8IRDBMSARC00739.001'
ORA-27041: unable to open file
OSD-04002: unable to open file
O/S-Error: (OS 2) 系統找不到指定的文件。

SQL> alter database open resetlogs;
Database altered.

2.無歸檔日誌
如果沒有歸檔日誌,由於restore出來是沒有在線日誌的。
如果v$datafile_header中checkpoint_change#是相同的,此時由於控制文件中checkpoint_change#比數據文件頭中要高,所以數據庫還是需要做media recovery。
此時重建控制文件還是一樣的,因爲重建控制文件後,在控制文件中checkpoint_change#爲0,與文件頭的checkpoint_change#還是不一樣,還需要media recovery.且由於控制文件中checkpoint_change#比文件頭中要高,所以做recover時還需要加上using backup controlfile.
注意,這時由於沒有在線日誌,所以重建控制文件需要將noresetlogs改成RESETLOGS纔可以創建成功,否則會報以下錯誤:
ORA-01565: error in identifying file 'D:ORACLE8IORADATAORA8IREDO01.LOG'
ORA-27041: unable to open file
如:
CREATE CONTROLFILE REUSE DATABASE "ORA8I" RESETLOGS ARCHIVELOG
MAXLOGFILES 32
MAXLOGMEMBERS 2
MAXDATAFILES 254
MAXINSTANCES 1
MAXLOGHISTORY 226
LOGFILE
GROUP 1 'D:ORACLE8IORADATAORA8IREDO01.LOG' SIZE 1M,
GROUP 2 'D:ORACLE8IORADATAORA8IREDO02.LOG' SIZE 1M,
GROUP 3 'D:ORACLE8IORADATAORA8IREDO03.LOG' SIZE 1M
DATAFILE
'D:ORACLE8IORADATAORA8ISYSTEM01.DBF',
'D:ORACLE8IORADATAORA8IRBS01.DBF',
'D:ORACLE8IORADATAORA8IUSERS01.DBF',
'D:ORACLE8IORADATAORA8ITEMP01.DBF',
'D:ORACLE8IORADATAORA8ITOOLS01.DBF',
'D:ORACLE8IORADATAORA8IINDX01.DBF'
CHARACTER SET ZHS16GBK
;
此時scn號信息如下:
SQL> select CHECKPOINT_CHANGE#,CONTROLFILE_CHANGE# from v$database;
CHECKPOINT_CHANGE# CONTROLFILE_CHANGE#
------------------ -------------------
0 0

此時由於沒有歸檔日誌和在線日誌,無法做recovery。
SQL> recover database using backup controlfile until cancel;
ORA-00279: change 2156662342 generated at 10/07/2005 17:06:27 needed for thread 1
ORA-00289: suggestion : D:ORACLE8IRDBMSARC00749.001
ORA-00280: change 2156662342 for thread 1 is in sequence #749
Specify log: {=suggested | filename | AUTO | CANCEL}
cancel
ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would get error below
ORA-01152: file 1 was not restored from a sufficiently old backup
ORA-01110: data file 1: 'D:ORACLE8IORADATAORA8ISYSTEM01.DBF'
ORA-01112: media recovery not started
所以也就無法做alter database open Resetlogs了。
此時可以加上_allow_resetlogs_corruption隱含參數,然後就可以alter database open resetlogs將數據庫打開了。

當然如果v$datafile_header中checkpoint_change#是不相同的,那麼此時就沒有什麼常歸有效的辦法能將數據庫打開了。
如果相差不多,加上隱含參數_allow_resetlogs_corruption,然後alter database open resetlogs還是有可能可以打開的。這個參數oracle是不建議加的,且加上這個參數也只是有可能可以打開。這個參數是以最oldest的scn將數據庫打開,所以最好system數據文件的scn號是最oldest的,否則容易產生大量的600號錯誤。
[The End]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章