SCN是當Oracle資料更新後,由DBMS自動維護去累積遞增的一個數字。 當一個交易commit時,LGWR會將log buffer寫入redo log file,同時也會將該筆交易的 SCN同步寫入到redo log file內(wait-until-completed)。因此當你commit transaction時, 在交易成功的訊息返回之前,LGWR必須先完整的完成上述行為之後,否則你是看不到提交成功的回應訊息。
我們可以查詢目前系統最新的SCN
select dbms_flashback.get_system_change_number from dual;
可以理解的,這裡返回的SCN,也是目前redo log file最新的SCN紀錄。 因為commit後的交易才會有SCN,而一旦commit就會立刻寫入redo log file中。
CHECKPOINT 和 SCN 的關連
checkpoint發生的目的就是要把儲存在buffer內的已提交交易寫回disk,否則一旦發生crash,需要 進行recovery時,你就必須花很多的時間從redo log file內最後的SCN交易開始進行recovery,這樣 在商業應用上是很浪費時間和沒有效率的。
重點在於當commit一個交易時,只會立刻將redo buffer寫入redo log file內,但是並不會馬上將 該update後的block(dirty block)同步寫回disk datafile中,這是為了減少過多disk IO的考量,所以採取batch的方式寫入。
When a checkpoint occurs, Oracle must update the headers of all datafiles to record the details of the checkpoint. This is done by the CKPT process. The CKPT process does not write blocks to disk; DBWn always performs that work.
在shutdown normal or shutdown immediate下,也就是所謂的clean shutdown,checkpoint也會自動觸發,並且把SCN紀錄寫回。 當發生checkpoint時,會把SCN寫到四個地方去。三個地方於control file內,一個在datafile header。
Control file三個地方為
1.System checkpoint SCN ===========> (SYSTEM CHECKPOINT SCN in control file)
SQL> select checkpoint_change# from v$database;
CHECKPOINT_CHANGE#
--------------------
292767
2.Datafile checkpoint SCN ===============> (DATAFILE CHECKPOINT SCN in control file)
SQL> select name,checkpoint_change#
from v$datafile where name like '%users01%';
NAME CHECKPOINT_CHANGE#
----------------------------------- --------------------
/u02/oradata/OMFD1/users01.dbf 292767
3.Stop SCN ======================> (STOP SCN in control file)
SQL> select name,last_change#
from v$datafile where name like '%users01%';
NAME LAST_CHANGE#
----------------------------------- ------------
/u02/oradata/OMFD1/users01.dbf
正常datafile在read-write mode咦飨拢琇ast_change#一定是NULL
另外一個地方在datafile header內
4.Start SCN ================================> (DATAFILE HEADER)
SQL> select name,checkpoint_change#
from v$datafile_header where name like '%users01%';
NAME CHECKPOINT_CHANGE#
----------------------------------- --------------------
/u02/oradata/OMFD1/users01.dbf 292767
為什麼儲存在CONTROL FILE中要分為兩個地方(SYSTEM CHECKPOINT SCN,DATAFILE CHECKPOINT SCN ?) 當你把一個tbs設為read-only時,他的SCN會凍結停止,此時DATAFILE CHECKPOINT SCN是不會再遞增改變的, 但是整體的SYSTEM CHECKPOINT SCN卻仍然會不斷遞增前進。
所以,這就是為什麼需要分別在兩個地方儲存SCN。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
正常shutdown database後,SCN會發生什麼變化?
我們可以把資料庫開在mount mode
select checkpoint_change# from v$database;
CHECKPOINT_CHANGE#
--------------------
293184
select name,checkpoint_change#,last_change# from v$datafile where name like '%user%';
NAME CHECKPOINT_CHANGE# LAST_CHANGE#
----------------------------------- -------------------- --------------
/u02/oradata/OMFD1/users01.dbf 293184 293184
可以看到儲存在control file中的三個SCN位置都是相同,注意此時的stop scn不會是NULL,而是等於start scn
我們也來查詢datafile header SCN:
select name,checkpoint_change# from v$datafile_header where name like '%users01%';
NAME CHECKPOINT_CHANGE#
----------------------------------- --------------------
/u02/oradata/OMFD1/users01.dbf 293184
當clean shutdown 時,checkpoint會進行,並且此時datafile的stop scn和start scn會相同。 等到我門開啟資料庫時,Oracle檢查datafile header中的start scn和存於control file中的datafile的scn是否相同, 如果相同,接著檢查start scn和stop scn是否相同,如果仍然相同,資料庫就會正常開啟,否則就需要recovery... 等到資料庫開啟後,儲存在control file中的stop scn就會恢復為NULL值,此時表示datafile是open在正常模式下了。
如果不正常SHUTDOWN (shutdown abort),則mount資料庫後,你會發現stop scn並不是等於其他位置的scn, 而是等於NULL,這表示Oracle在shutdown時沒有進行checkpoint,下次開機必須進行crash recovery。
crash recovery
必須先進行roll forward(從redo log file中從目前的start SCN開始,重做後面的已提交之交易)
再從roll back segment 做rollback未完成(dead transaction)交易
檢驗controlfile中的SCN會等於datafile header的SCN
select 'controlfile' "SCN location",name,checkpoint_change#
from v$datafile where name like '%users01%'
union
select 'file header',name,checkpoint_change#
from v$datafile_header where name like '%users01%';
SCN location NAME CHECKPOINT_CHANGE#
-------------- ----------------------------------- --------------------
controlfile /u02/oradata/OMFD1/users01.dbf 293188
file header /u02/oradata/OMFD1/users01.dbf 293188
crash recovery vs media recovery
啟動資料庫時,如果發現STOP SCN = NULL,表示需要進行crash recovery;啟動資料庫時,如果發現有datafile header的START SCN 不等於儲存於CONTROLFILE的DATAFILE SCN,表示需要進行Media recovery
STOP SCN equal NULL ==> NEED CRASH RECOVERY
DATAFILE HEADER START SCN not equal CONTROLFILE SCN ==> NEED MEDIA RECOVERY
RECOVERY DATABASE 兩種常見問題
1) RECOVER DATABASE UNTIL CANCEL ==> OPEN DATABASE RESETLOG
==> DATAFILE HEADER SCN一定會小於CONTROLFILE的DATAFILE SCN
如果你有進行RESTORE DATAFILE,則該RESTORE的DATAFILE HEADER SCN一定會小於目前CONTROLFILE的DATAFILE SCN,此時會無法
開啟資料庫,必須進行media recovery~~重做archive log直到該datafile header的SCN=current scn
restore datafile後,可以mount database然後去檢查controlfile and datafile header的SCN
select 'controlfile' "SCN location",name,checkpoint_change#
from v$datafile where name like '%users01%'
union
select 'file header',name,checkpoint_change#
from v$datafile_header where name like '%users01%';
SCN location NAME CHECKPOINT_CHANGE#
-------------- ----------------------------------- --------------------
controlfile /u02/oradata/OMFD1/users01.dbf 313551
file header /u02/oradata/OMFD1/users01.dbf 313401
2) RECOVER DATABASE UNTIL CANCEL USING BACKUP CONTROLFILE; ===> OPEN DATABASE RESETLOG
==> DATAFILE HEADER SCN一定會大於CONTROLFILE的DATAFILE SCN
如果只是某TABLE被DROP掉,沒有破壞資料庫整體資料結構,還可以用INCOMPLETE RECOVERY解決 如果是某個TABLESPACE OR DATAFILE被DROP掉,因為檔案結構已經破壞,目前的CONTROL FILE內已經沒有 該DATAFILE的資訊,就算你只RESTORE DATAFILE然後進行INCOMPLETE RECOVERY也無法救回被DROP的DATA FILE。
只好RESOTRE 之前備份的CONTROL FILE(裡頭被DROP DATAFILE Metadata此時還存在),不過RESTOREC CONTROL FILE後 此時Oracle會發現CONTROL FILE內的SYSTEM SCN會小於目前的DATAFILE HEADER SCN,也不等於目前儲存於LOG FILE內的SCN, 此時就必須使用RECOVER DATABASE UNTIL CANCEL USING BACKUP CONTROLFILE到DROP DATAFILE OR DROP TABLESPACE之前的SCN。
另一種特殊狀況就是,萬一不幸地所有CONTROL FILE都遺失了,也必須用這種方式救回,所以請做MULTIPLEXING。
/*************the other article*****************/
检查点SCN深入研究
一、检查点概述
大多数关系型数据库都采用"在提交时并不强迫针对数据块的修改完成"而是"提交时保证修改记录(以重做日志的形式)写入日志文件"的机制,来获得性能的优势。这句话的另外一种描述是:当用户提交事务,写数据文件是"异步"的,写日志文件是"同步"的。这就可能导致数据库实例崩溃时,内存中的DB_Buffer 中的修改过的数据,可能没有写入到数据块中。数据库在重新打开时,需要进行恢复,来恢复DB Buffer 中的数据状态,并确保已经提交的数据被写入到数据块中。检查点是这个过程中的重要机制,通过它来确定,恢复时哪些重做日志应该被扫描并应用于恢复。
要了解这个检查点,首先要知道checkpoint queu概念,检查点发生后,触发dbwn,CKPT获取发生检查点时对应的SCN,通知DBWn要写到这个SCN为止,
dbwr 写dirty buffer 是根据 buffer 在被首次 modify的时候的时间的顺序写出,也就是 buffer被modify 的时候会进入一个queue (checkpoint queue),dbwr 就根据queue从其中批量地写到数据文件。 由于这里有一个顺序的关系,所以 dbwr的写的进度就是可衡量的,写到哪个buffer的时候该buffer的首次变化时候的scn就是当前所有数据文件block的最新scn,但是由于无法适时的将dbwr的进度记录下来,所以oracle 选择了一些策略。 其中就包括ckpt进程的检查点和心跳。
检查点发生以后,CKPT进程检查checkpoint queue(也就是脏块链表)是否过长,如果是,则触发DBWn,将一部分脏块写入数据文件,从而缩短checkpoint queue。
checkpoint 发生时,一方面通知dbwr进行下一批写操作,(dbwr 写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。)另一方面,oracle 采用了一个心跳的概念,以3秒的频率将dbwr 写的进度反应到控制文件中,也就是把dbwr当前刚写完的dirty buffer对应的scn 写入数据文件头和控制文件,这就是检查点scn。
这个3秒和增量检查点不是一个概念,3秒只是在控制文件中,ckpt 进程去更新当前 dbwr写到哪里了,这个对于 ckpt 进程来说叫 heartbeat ,heartbeat是3秒一次,3秒可以看作不停的检查并记录检查点执行情况(DBWR的写进度)。
检查点发生之后数据库的数据文件、控制文件处于一致状态的含义是不需要进行 介质恢复,只表示数据文件头一致,但是并不表示数据文件内容一致,因为数据文件内容可能在没有发生检查点的其他情况下的dbwr写数据文件,这样数据文件内容就不一致,若掉电需要进行崩溃恢复。
二、触发的条件
这里需要明白两个概念"完全检查点和增量检查点"的区别。
增量检查点(incremental checkpoint)
oracle8以后推出了incremental checkpoint的机制,在以前的版本里每checkpoint时都会做一个full thread checkpoint,这样的话所有脏数据会被写到磁盘,巨大的i/o对系统性能带来很大影响。为了解决这个问题,oracle引入了checkpoint queue机制,每一个脏块会被移到检查点队列里面去,按照low rdb(第一次对此块修改对应的redo block address)来排列,靠近检查点队列尾端的数据块的low rba值是最小的,而且如果这些赃块被再次修改后它在检查点队列里的顺序也不会改变,这样就保证了越早修改的块越早写入磁盘。每隔3秒钟ckpt会去更新控制文件和数据文件,记录checkpoint执行的情况。
在运行的Oracle 数据中,有很多事件、条件或者参数来触发检查点。比如
当已通过正常事务处理或者立即选项关闭例程时;(shutdown immediate或者Shutdown normal;)
当通过设置初始化参数LOG_CHECKPOINT_INTERVAL、LOG_CHECKPOINT_TIMEOUT 和FAST_START_IO_TARGET 强制时;
当数据库管理员手动请求时;(ALter system checkpoint)
alter tablespace ... offline;
每次日志切换时;(alter system switch logfile)
需要说明的是,alter system switch logfile也将触发完全检查点的发生。
alter database datafile ... offline不会触发检查点进程。
如果是单纯的offline datafile,那么将不会触发文件检查点,只有针对offline tablespace的时候才会触发文件检查点,这也是为什么online datafile需要media recovery而online tablespace不需要。
对于表空间的offline后再online这种情况,最好做个强制的checkpoint比较好。
上面几种情况,将触发完全检查点,促使DBWR 将检查点时刻前所有的脏数据写入数据文件。
另外,一般正常运行期间的数据库不会产生完全检查点,下面很多事件将导致增量检查点,比如:
在联机热备份数据文件前,要求该数据文件中被修改的块从DB_Buffer 写入数据文件中。所以,发出这样的命令:
ALTER TABLESPACE tablespace_name BIGEN BACKUP & end backup; 也将触发和该表空间的数据文件有关的局部检查点;另外,
ALTER TABLESPACE tablespace_name READ ONLY;
ALTER TABLESPACE tablespace_name OFFLINE NORMAL;
等命令都会触发增量检查点。
关于检查点的一点具体应用讨论:
Commit成功后,数据还会丢失吗?
对于Oracle来说,用户所做的DML操作一旦被提交,则先是在database buffer cache 中进行修改,同时在修改之前会将数据的前镜像保存在回滚段中,然后将修改之前和修改之后的数据都写入到redo log buffer中,当接收到commit命令之后,则redo log buffer开始写redo log file ,并且记录此时的scn,当redo log file 写完了之后,表示这次事务提交操作已经确认被数据库记录了,只有当redo log file 写成功了,才会给用户 Commit completed 的成功字样。而对于Database buffer cache中的dirty buffer则会等待触发DBWn才写入,但是如果此时断电,则数据已经被记录到了redo log file中,系统在重新启动的时候,会自动进行嵌滚和回滚来保证数据的一致。所以,只要是commit成功的了,数据不会丢失!
数据库发生一次DBWn,是否将所有buffer cache 中的dirty buffer 都写入,还是先将脏队列中的数据写入?
这话看起来有道理,但实际上,dbwr在写的时候又不断地在产生dirty buffer ,所以说检查点发生的时候是期望把该时间点之前的所有脏缓冲区写入数据文件。
所有的buffer,不在LRU list上就在dirty list上, dbwr写入的时候,一次写的块数是有一个批量写的隐藏参数控制的。
所以说要是 dbwr将 dirty list也好, lru list上的也好,要实现全部写入,都是一个现实系统中很难存在的现象。dirty 总是在不断的产生,dbwr总是在不断地写,增量检查点发生的时候也并不意味着一定要更新数据文件头,检查点开始的时候只表示该次检查点结束的时候要更新数据文件头的话数据文件头具有该时间点的一致性。
关于检查点等待事件:
有些事件的产生必须等待检查点的完成,才能开始数据库的其它操作:
日志文件切换就是其中一个事件,日志切换必须等待检查点完成。
log file switch (checkpoint incomplete) 这个等待事件本身也说明,日志切换时产生的检查点是需要等待的,这个日志文件所对应脏块全部写完后,检查点进程更新控制文件和数据头,然后这个检查点才能算完成。
也就是说日志切换必须等待检查点完成,而检查点在等待DBWn完成。
这种等待DBWn完成的检查点,最后一步写入控制文件和数据文件头的SCN,肯定是DBWn完成的最后一块的SCN。
检查点为什么要等待dbwr完成后才进行切换(log switch)?
log switch时,是不能立即switch到active状态的,log group必须等待。active表示该log group还没有完成归档(归档模式下)或者该log group有进行instance recovery的需要用到的日志。所以当checkpoint发生时,如果dbwr还没有写完它该写完的dirty buffers(该checkpoint时间点以前产生的dirty buffers, 靠scn判断),则该log group处于active状态,不会进行日志切换,当然也不会发生日志文件被覆盖的问题了。
如果没有设置archive log ,在检查点发生后,发生log switch一个轮回,log file是否会被覆盖掉?
当检查点发生后,会触发lgwr,lgwr会把此时SCN以前在redo buffer中的所有操作写到redo log file,同时lgwr也会触发dbwr进程,dbwr也开始把此刻以前database buffer中的dirty buffer队列中的操作写入data file。
其实检查点发生后,就是lgwr和dbwr写buffer到磁盘文件的过程,但是两者的读写速度时不同的,dbwr写buffer到数据文件的过程相对较慢,因为dbwr写过程是一个随机读取存储的过程。Lgwr写buffer到redo文件的过程比dbwr要快很多,因为lgwr是顺序读取写入的。
由于以上lgwr和dbwr写操作的速度不同,就产生了一个等待问题。即当lgwr
轮循一圈后,要进行日志切换,覆盖redo log file,但是此时dbwr还没有写完,那么lgwr就会出现等待,oracle也会hang在那里,同时alter文件中会提示一个相应的提示checkpoint not complete。等检查点完成后数据库自动恢复正常。
当log switch时,会触发检查点,标记检查点时,DBWR要把log file中covered by the log being checkpointed的数据写入到数据文件上,如果Dbwr没有写完,那么前一个logfile是不能被覆盖的。因此必须等检查点完毕,也可以说是将 要被覆盖的日志相关的数据块全部写入数据文件后,该日志文件才能被覆盖!
如果这种情况出现,alert文件中会记录checkpoint not complete事件,这通常表明你的dbwr写入过慢或者logfile组数过少或log file太小。
检查点发生时,出现日志切换,但是dbwr还没有写完,是否会覆盖redo log file,如果此时掉电,dbwr挂起,会出现丢失数据吗?
答:不会覆盖redo文件,要等待dbwr写完才覆盖。或者说要等待检查点完成才覆盖。
如果DBWn正在写的脏块是指对应到即将被覆盖的那个日志文件的,那么,因为在这些操作完成之前,不可能有覆盖这件事发生,假设你预料的掉电发生了,不会有什么问题,实例恢复时的前滚从刚才准备覆盖的那个日志文件开始。
如果正在写的脏块是指对应到刚刚被写满的那个日志文件的,肯定一时半会也写不完,日志切换也不会等它,如果切换成功后dbwr挂了,后面的写脏块操作估计也还没完成,但是,刚写满的那个文件并没有被覆盖,也不会有任何问题。
因此不会出现数据丢失!
当一个很大的dml发生时,用户在commit后,需要将redo log buffer中的脏数据写入redo log file中。如果在写的过程中,发现一个redo log file写不下的话,需要写另外一个redo log file,这时应该触发checkpoint,接着触发DBWn,将脏数据写入datafile,这时发生掉电,导致DBWR失败。这时其实就可以说commit失败了。以上所述其实就是commit没有提交成功。
alter systen switch logfile会触发完全检查点;但是为什么,日志切换以后检查点只能记录到上一次归档日志产生的时间呢?而不是现在归档日志产生的时间呢?
因为这时的checkpoint enqueue队列中,也就是脏块队列中脏块还不够多,还不足以触发DBWn写脏块。所以,内存里需要写入的脏块所对应的redo还存在于上一个redo log里,这时你去看该redo log的status为active。
下面操作日志中出现当前redo log的status为current,而上一个redo log的status为active就说明了这一切。上一个redo log的status为active正是说明在上一个redo log中还存在未写入datafile的block所对应的redo。
SQL> create table gaojf3 as select * from all_objects;
Table created
SQL> insert into gaojf3 select * from gaojf3;
29630 rows inserted
SQL> /
59260 rows inserted
SQL> commit;
Commit complete
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 1 14 8796117861680 08/02/2006 02:29:36 0 13 cicro 08/02/2006 02:33:50
SQL> alter system switch logfile;
System altered
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 2 15 8796117861680 08/02/2006 02:29:36 0 14 cicro 08/02/2006 02:33:50
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119126928 08/08/2006 00:28:38 1 14 2 16 0200000000000000 0 0 3 1 3 2 15 8796117861680 08/02/2006 02:29:36 0 14 cicro 08/02/2006 02:33:50
SQL> select * from x$kccrt;
ADDR INDX INST_ID RTNUM RTSTA RTCKP_SCN RTCKP_TIM RTCKP_THR RTCKP_RBA_SEQ RTCKP_RBA_BNO RTCKP_RBA_BOF RTCKP_ETB RTOTF RTOTB RTNLF RTLFH RTLFT RTCLN RTSEQ RTENB RTETS RTDIS RTDIT RTLHP RTSID RTOTS
-------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------- ------------- ------------- ------------- ---------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------------- -------------------- ---------------- -------------------- ---------- ---------------- --------------------
421A54D0 0 1 1 15 8796119128114 08/08/2006 00:35:51 1 15 2 16 0200000000000000 0 0 3 1 3 3 16 8796117861680 08/02/2006 02:29:36 0 15 cicro 08/02/2006 02:33:50
从上面试验中可以看到,完全检查点正在执行,还没有执行完毕。因此,切换日志前后察看x$kccrt,看到的RTCKP_SCN, RTCKP_TIM没有发生变化。等检查点执行完毕后(也就是检查点触发的dbwr执行完写操作后),rtckp_scn, rtckp_tim才发生变化。
.
/*********************************logzgh**********************************************/
scn号与oracle数据库恢复过程有着密切的关系,只有很好地理解了这层关系,才能深刻地理解恢复的原理,从而才能很好地解决这方面的问题。
一。SCN与CHECKPOINT
CKPT进程在checkpoint发生时,将当时的SCN号写入数据文件头和控制文件,同时通知DBWR进程将数据块写到
数据文件。
CKPT进程也会在控制文件中记录RBA(redo block 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号
ORACLE将End SCN号存放在控制文件中。
这个SCN号用于检查数据库启动过程是否需要做instance recovery.
我们可以通过以下SQL语句查询:
select name,last_change# from v$datafile;
在数据库正常运行的情况下,对可读写的,online的数据文件,该SCN号为NULL.
二。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。这是为什么需要记录System
Checkpoint SCN的原因之一。
这里需要一提的是,当重建控制文件的时候,System Checkpoint SCN为0,Datafile Checkpoint SCN
的数据来自于Start SCN。根据上述的描述,此时需要采用using backup controlfile做recovery.
六。示例
例子背景:
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号错误。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/7301064/viewspace-410879/ ,如需转载,请注明出处,否则将追究法律责任。