揭密備份恢復的原理

楊奇龍發表於2010-06-06
其實一句話就可以說明白:那就是資料檔案的頭上不僅包含了checkpoint_change#,更重要的是它包含了這個 checkpoint_change#所在的logfile的sequence#,準確的說是rba有了rba,在恢復時就能準確的知道到底需要哪個 logfile(archivelog or redo)。
結果花了很大篇幅,只想以試驗的方式做個簡單的驗證,便於大家理解。歡迎拍磚!
另外提個問題:是否存在一些資料字典它是源於redo的?

--controlfile中記錄的checkpoint_change#
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1951985
--datafile中記錄的checkpoint_change#
SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00

--controlfile中記錄的每一個datafile的checkpoint_change#
SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00
           1951985 2008/10/01 14:17:00

--controlfile中記錄的redo的checkpoint_change#
SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1951985 2008/10/01 14:17:00

SQL> alter system checkpoint;


系統已更改。
--檢查點發生之後,上面提到的checkpoint_change#都給更新
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1955601

SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26

SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26
           1955601 2008/10/01 16:15:26

SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955601 2008/10/01 16:15:26

SQL> shutdown immediate
資料庫已經關閉。
已經解除安裝資料庫。
ORACLE 例程已經關閉。
--冷備份db,為下面的恢復試驗使用
SQL> startup mount
ORACLE 例程已經啟動。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes

資料庫裝載完畢。
--檢視備份時刻的checkpoint_change#,此時的checkpoint_change#=1955692
是例項shutdown時系統所做的完全檢查點對應的checkpoint_change#,下面
在恢復時還會看到這個checkpoint_change#:1955692
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1955692

SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24

SQL> alter database open;

資料庫已更改。
--輸入測試資料,驗證備份恢復的過程,注意仔細觀查插入到tt表中的dbms_flashback.get_system_change_number
和v$log中的FIRST_CHANGE#之間的關係,我們通常理解備份恢復的原理是:事務對應的scn如果落在了哪個archivelog
裡,那麼這個archivelog在恢復時就被用到,下面的大致試驗過程也會驗證這一點:

SQL> connect test/test
已連線。
SQL> select group#,status,sequence#,archived,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 INACTIVE                 74 YES       1926639
         2 CURRENT                  76 NO        1951985
         3 INACTIVE                 75 YES       1947901

SQL> truncate table tt;

表被截斷。

SQL> desc tt
名稱                                      是否為空? 型別
----------------------------------------- -------- ----------------------------

ID                                                 NUMBER(38)
NAME                                               VARCHAR2(10)

SQL> insert into tt values(dbms_flashback.get_system_change_number,'a');

已建立 1 行。

SQL> commit;

提交完成。

SQL> connect / as sysdba
已連線。
--datafile header上記錄的rba資訊,rba的意義在下面做了詳細解釋,這裡只需
知道FHRBA_SEQ表示redo的sequence#=76對應的是當前聯機日誌,而該sequence#被
記錄在了datafile header上

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         76       6618         16
         2         76       6618         16
         3         76       6618         16
         4         76       6618         16

SQL> select group#,status,sequence#,archived,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 INACTIVE                 74 YES       1926639
         2 CURRENT                  76 NO        1951985
         3 INACTIVE                 75 YES       1947901
SQL> insert into test.tt values(dbms_flashback.get_system_change_number,'b');

已建立 1 行。

SQL> commit;

提交完成。

SQL> alter system switch logfile;

系統已更改。

SQL> select group#,status,sequence#,archived,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 CURRENT                  77 NO        1956233
         2 ACTIVE                   76 YES       1951985
         3 INACTIVE                 75 YES       1947901

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         76       6618         16
         2         76       6618         16
         3         76       6618         16
         4         76       6618         16

SQL> alter system checkpoint;

系統已更改。

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         77          9         16
         2         77          9         16
         3         77          9         16
         4         77          9         16

SQL> select * from test.tt;

        ID NAME
---------- ----------
   1956113 a
   1956225 b

SQL> select group#,status,sequence#,archived,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 CURRENT                  77 NO        1956233
         2 INACTIVE                 76 YES       1951985
         3 INACTIVE                 75 YES       1947901

SQL> insert into test.tt values(dbms_flashback.get_system_change_number,'c');

已建立 1 行。

SQL> commit;

提交完成。

SQL> select group#,status,sequence#,archived,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 CURRENT                  77 NO        1956233
         2 INACTIVE                 76 YES       1951985
         3 INACTIVE                 75 YES       1947901

SQL> alter system switch logfile;

系統已更改。

SQL> select * from test.tt;

        ID NAME
---------- ----------
   1956113 a
   1956225 b
   1956317 c

SQL> select group#,status,sequence#,archived,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 ACTIVE                   77 YES       1956233
         2 INACTIVE                 76 YES       1951985
         3 CURRENT                  78 NO        1956324
SQL> insert into test.tt values(dbms_flashback.get_system_change_number,'d');

已建立 1 行。

SQL> commit;

提交完成。

SQL> alter system switch logfile;

系統已更改。

SQL> select * from test.tt;

        ID NAME
---------- ----------
   1956113 a
   1956225 b
   1956317 c
   1956472 d
--總共往tt表裡插入了4條資料,對應的id值(透過dbms_flashback.get_system_change_number獲得的)
都大於sequence#=76所對應的first_change#:1951985,因此在恢復db時
sequence#=76的歸檔日誌會被用到,還會用到那些歸檔日誌呢?

要看tt表中對應的id值落在了那些歸檔日誌的FIRST_CHANGE#和NEXT_CHANGE#之內,
如果落在其中,則恢復時這個歸檔日誌就會被用到,就這個例子而言,76,77,78號歸檔日誌
在恢復db時都會被用到,接下來的恢復過程也會驗證這一點

SQL> select sequence#,first_change#,next_change#  from v$archived_log
  2  where sequence# in (76,77,78) and resetlogs_id=666280390;

SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#
---------- ------------- ------------
        76       1951985      1956233
        77       1956233      1956324
        78       1956324      1956480
--透過dump datafile header中的資訊發現datafile header上不僅記錄了checkpoint_change#,
更重要的是記錄了checkpoint_change#所在的redo sequence#:

SQL> alter session set events 'immediate trace name FILE_HDRS level 12';

會話已更改。
trace file中最有用的資訊莫過於:
Checkpointed at scn:  0x0000.001dd9e4 10/01/2008 16:30:40 --checkpoint_change#
thread:1 rba:(0x4e.2.10) --sequence# (rba的含義在下面會有詳細介紹)
SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         79          2         16
         2         79          2         16
         3         79          2         16
         4         79          2         16


SQL> shutdown immediate
資料庫已經關閉。
已經解除安裝資料庫。
ORACLE 例程已經關閉。
--複製備份的datafile回來
SQL> startup
ORACLE 例程已經啟動。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes

資料庫裝載完畢。
ORA-01113: 檔案 1 需要介質恢復
ORA-01110: 資料檔案 1: 'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF'


--為什麼會發出"檔案 1 需要介質恢復"這樣的提示,是因為controlfile
中記錄的checkpoint_change#是:1967625,而datafile header上記錄的
checkpoint_change#是:1955692

SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1967625

SQL> select checkpoint_change# ,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change# ,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1967625 2008/10/01 19:06:21
           1967625 2008/10/01 19:06:21
           1967625 2008/10/01 19:06:21
           1967625 2008/10/01 19:06:21

SQL> select checkpoint_change# ,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1967625 2008/10/01 19:06:21
--下面透過dump datafile header中的資訊來觀查checkpoint_change#和rba的資訊,來看看
oracle到底在恢復時是如何使用歸檔日誌的

SQL> alter session set events 'immediate trace name FILE_HDRS level 12';

會話已更改。
trace file中每個datafile都有一段對應的描述,內容摘錄如下:
DATA FILE #1:
  (name #7) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF
...............................中間無關內容省略
--==================================
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--oracle在恢復時最有用的就是Checkpointed at scn:0x0000.001dd76c和
thread:1 rba:(0x4c.19da.10)了
--======================================
DATA FILE #2:
  (name #1) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\TEST.DBF
....................................中間無關內容省略
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--=======================================
DATA FILE #3:
  (name #5) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSAUX01.DBF
....................................中間無關內容省略
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--=======================================
DATA FILE #4:
  (name #6) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\UNDOTBS01.DBF
....................................中間無關內容省略
Checkpointed at scn:  0x0000.001dd76c 10/01/2008 16:17:24
thread:1 rba:(0x4c.19da.10)
--=======================================
--而上面trace file中記錄的Checkpointed at scn:0x0000.001dd76c
轉化為10進位制數:
SQL> select to_number('001dd76c','xxxxxxxx') from dual;

TO_NUMBER('001DD76C','XXXXXXXX')
--------------------------------
                         1955692

而1955692正是我們在最開始備份時記錄下來的checkpoint_change#,另外檢查點發生的時間其實也是
吻合的:10/01/2008 16:17:24,也許有人說查詢:
select checkpoint_change#,checkpoint_time from v$datafile_header;
其實讀取的就是資料檔案頭,結果當然是一樣的,呵呵,沒錯,不論是上面查詢還是dump datafile header
其實資訊的來源都是來自datafile header。只是dump出來我們看的更加直觀一些,其實在資料字典中也提供了
類似的資訊,如上面執行的查詢:
select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;
為什麼要查詢x$kcvfh,是因為x$kcvfh是v$datafile_header的源,這個大家可以檢視
v$fixed_view_definition而得知。
其實fhrba_seq,fhrba_bno,fhrba_bof這3個欄位對應的就是rba,rba的意思是:
Recent entries in the redo thread of an Oracle instance are addressed using a 3-part redo byte address, or RBA. An RBA is comprised of
the log file sequence number (4 bytes)
the log file block number (4 bytes)
the byte offset into the block at which the redo record starts (2 bytes)
在datafile header上記錄rba,在恢復時就能非常準確的知道需要哪個日誌檔案(透過the log file sequence number)以及哪個block(透過the log file block number)以及
在這個日誌block上從哪個byte開始讀取恢復(透過the byte offset)

--=========================================
下面我們來接著上面開啟db時的提示來恢復db,驗證一下:
SQL> alter database open;
alter database open
*
第 1 行出現錯誤:
ORA-01113: 檔案 1 需要介質恢復
ORA-01110: 資料檔案 1: 'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF'


SQL> recover database;
ORA-00279: 更改 1955692 (在 10/01/2008 16:17:24 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

76_%U_.ARC
ORA-00280: 更改 1955692 (用於執行緒 1) 在序列 #76 中


指定日誌: {=suggested | filename | AUTO | CANCEL}

--====================================
--這裡為什麼會從1955692開始恢復db,原因當然就是備份時db發生檢查點
其對應的checkpoint_change#是1955692,這個我們在最開始的時候就提到過,說
在備份時會用到這個值:1955692,那麼序列#76就是如何來的呢?
其實就是從rba轉化來得:備份時候datafile header的dump資訊上面已經顯示出來了,
其實rba是:thread:1 rba:(0x4c.19da.10)
根據rba表示的意義把4c轉化成10進位制數不正是:4*16+12(16進位制的c)=76
,那麼sequence#=76的歸檔日誌檔案O1_MF_1_76_%U_.ARC其實並不會在恢復時完全用到,而是從
block:19da轉化為10進位制數是:
SQL> select to_number('19da','xxxx') from dual;

TO_NUMBER('19DA','XXXX')
------------------------
                    6618

也就是從6618#block開始恢復
下面開始恢復:
--========================================
接著上面要求恢復的提示敲回車:
ORA-00279: 更改 1956233 (在 10/01/2008 16:27:12 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

77_%U_.ARC
ORA-00280: 更改 1956233 (用於執行緒 1) 在序列 #77 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_76_4G6F313F_.ARC'


指定日誌: {=suggested | filename | AUTO | CANCEL}

--====================================
sequence#=76的日誌已經恢復,接下來需要77#日誌:
恢復時到底需要那些歸檔日誌可以透過檢視 v$recovery_log來獲得:
v$recovery_log的資訊就是透過比較control file中的checkpoint_change#
和datafile header上的checkpoint_change#而產生的,如果我們在恢復時
把備份的controlfile和datafile一同複製回來(不要複製redo),那麼肯定在
v$recovery_log不會查到任何資訊。

SQL> select sequence# from v$recovery_log;

SEQUENCE#
----------
        77
        78

SQL>
在76#歸檔日誌恢復之後再來觀察一下資料檔案頭上checkpoint_change#和rba的變化情況:
checkpoint_change#資訊:
SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1956233 2008/10/01 16:27:12
           1956233 2008/10/01 16:27:12
           1956233 2008/10/01 16:27:12
           1956233 2008/10/01 16:27:12

SQL>
rba資訊:
SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         77          2          0
         2         77          2          0
         3         77          2          0
         4         77          2          0

SQL>
此時再恢復db時會使用sequence#=77的歸檔日誌,同時是從第二個日誌block
開始使用的,因為日誌檔案頭佔用1個block,如果有人透過dd命令做過redo file
從檔案系統和raw轉化的話應該知道redo的頭佔用1個block,不過這個可能也和os有關的
,不同的os,redo的頭塊也可能會佔用不同個數的block,具體沒有做過太深入的研究。
--==========================
接著恢復:
ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用於執行緒 1) 在序列 #78 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'


指定日誌: {=suggested | filename | AUTO | CANCEL}

--==========================
查詢一下checkpoint_change#和rba的資訊:
上面透過查詢view驗證過了,這次dump 一下datafile header來看看:
SQL> alter session set events 'immediate trace name FILE_HDRS level 12';

會話已更改。
--=======================
trace file 主要資訊:(僅摘錄一個檔案的資訊,4個檔案的資訊其實都相同)
DATA FILE #1:
  (name #7) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF
..........................................(省去無關的資訊)
Checkpointed at scn:  0x0000.001dd9e4 10/01/2008 16:30:40
thread:1 rba:(0x4e.2.0)
--=======================
這裡只轉化一下sequence#:4e看看是否是78就可以了:
4*16+14(16進位制的e)=78
正好是78,也就是恢復時下一個要使用的歸檔日誌。
--=============================
接著恢復:
ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用於執行緒 1) 在序列 #78 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'


指定日誌: {=suggested | filename | AUTO | CANCEL}

已應用的日誌。
完成介質恢復。
SQL>
--===================================
78#歸檔日誌恢復之後checkpoint_change#可以達到1956480,透過下面查詢78#
歸檔日誌的next_change#可以得知:
SQL> select sequence#,first_change#,next_change#  from v$archived_log
  2  where sequence# in (76,77,78) and resetlogs_id=666280390;

SEQUENCE# FIRST_CHANGE# NEXT_CHANGE#
---------- ------------- ------------
        76       1951985      1956233
        77       1956233      1956324
        78       1956324      1956480

SQL>
但目前datafile header的checkpoint_change#和rba資訊是:
1967624以及81       1281         16,是因為在恢復時系統
自動讀取了聯機日誌。
SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1967624 2008/10/01 19:06:21
           1967624 2008/10/01 19:06:21
           1967624 2008/10/01 19:06:21
           1967624 2008/10/01 19:06:21

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         81       1281         16
         2         81       1281         16
         3         81       1281         16
         4         81       1281         16

SQL> select group#,status,sequence#,archived,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# ARC FIRST_CHANGE#
---------- ---------------- ---------- --- -------------
         1 INACTIVE                 80 YES       1961750
         3 CURRENT                  81 NO        1967088
         2 INACTIVE                 79 YES       1956480

SQL>
--oracle為什麼能自動讀取redo來恢復,是因為在controlfile中記錄了redo的資訊
SQL> select sequence#,checkpoint_change#,last_redo_change# from v$thread;

SEQUENCE# CHECKPOINT_CHANGE# LAST_REDO_CHANGE#
---------- ------------------ -----------------
        81            1967625           1967375

SQL>
--下面把最新的redo暫時隱藏起來,也就是說不讓其自動應用redo再來觀查一下
oracle是如何要尋找redo的:
SQL> shutdown immediate
ORA-01109: 資料庫未開啟


已經解除安裝資料庫。
ORACLE 例程已經關閉。
--複製備份的資料檔案,同時把redo隱藏起來
SQL> startup
ORACLE 例程已經啟動。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes
資料庫裝載完畢。
ORA-01113: 檔案 1 需要介質恢復
ORA-01110: 資料檔案 1: 'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\SYSTEM01.DBF'


SQL> recover database;
ORA-00279: 更改 1955692 (在 10/01/2008 16:17:24 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

76_%U_.ARC
ORA-00280: 更改 1955692 (用於執行緒 1) 在序列 #76 中


指定日誌: {=suggested | filename | AUTO | CANCEL}

ORA-00279: 更改 1956233 (在 10/01/2008 16:27:12 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

77_%U_.ARC
ORA-00280: 更改 1956233 (用於執行緒 1) 在序列 #77 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_76_4G6F313F_.ARC'


指定日誌: {=suggested | filename | AUTO | CANCEL}

ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用於執行緒 1) 在序列 #78 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'


指定日誌: {=suggested | filename | AUTO | CANCEL}

ORA-00283: 恢復會話因錯誤而取消
ORA-00313: 無法開啟日誌組 2 (用於執行緒 1) 的成員
ORA-00312: 聯機日誌 2 執行緒 1:
'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO02.LOG'
ORA-27041: 無法開啟檔案
OSD-04002: 無法開啟檔案
O/S-Error: (OS 2) 系統找不到指定的檔案。


ORA-01112: 未啟動介質恢復
--oracle為什麼會找REDO02.LOG,因為REDO02.LOG對應的sequence#是79,看看在controlfile中記錄的redo資訊就知道了
,v$log的資訊來自controlfile,這也說明了為什麼我們在恢復db時如果controlfile是最新的話那麼在恢復時redo會被自動應用,而
controlfile是從備份中恢復過來(也就是說controlfile不是最新的,是備份的,在恢復時需要使用using backup controlfile子句)
的話在恢復db時redo不會被自動應用,而需要我們手動輸入來嘗試看看oracle到底需要哪個redo


SQL> select group#,status,sequence#,first_change# from v$log;

    GROUP# STATUS            SEQUENCE# FIRST_CHANGE#
---------- ---------------- ---------- -------------
         1 INACTIVE                 80       1961750
         3 CURRENT                  81       1967088
         2 INACTIVE                 79       1956480

SQL>
--============================
驗證一下使用using backup controlfile自己恢復db時使用redo的情況:
SQL> shutdown immediate
ORA-01109: 資料庫未開啟


已經解除安裝資料庫。
ORACLE 例程已經關閉。
SQL>
--複製備份的datafile and controlfile以及最新的redo回來
SQL> startup
ORACLE 例程已經啟動。

Total System Global Area  163577856 bytes
Fixed Size                  1247876 bytes
Variable Size              92276092 bytes
Database Buffers           67108864 bytes
Redo Buffers                2945024 bytes
資料庫裝載完畢。
ORA-00314: 日誌 1 (用於執行緒 1) 要求的序號  與  不匹配
ORA-00312: 聯機日誌 1 執行緒 1:
'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO01.LOG'


SQL>
為什麼在open db時會發出這樣的提示:
看看controlfile and datafile_header中記錄的checkpoint_change#:
SQL> select checkpoint_change# from v$database;

CHECKPOINT_CHANGE#
------------------
           1955692

SQL> select checkpoint_change#,checkpoint_time from v$datafile_header;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$datafile;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24
           1955692 2008/10/01 16:17:24

SQL> select checkpoint_change#,checkpoint_time from v$thread;

CHECKPOINT_CHANGE# CHECKPOINT_TIME
------------------ -------------------
           1955692 2008/10/01 16:17:24

SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         76       6618         16
         2         76       6618         16
         3         76       6618         16
         4         76       6618         16

SQL> select group#,status,sequence#, first_change# from v$log;

    GROUP# STATUS            SEQUENCE# FIRST_CHANGE#
---------- ---------------- ---------- -------------
         1 INACTIVE                 74       1926639
         3 INACTIVE                 75       1947901
         2 CURRENT                  76       1951985
--很顯然v$log的資訊是來自controlfile的,和上面新的controlfile中記錄的
v$log的資訊對比,當然doc上也明確提到v$log的資訊來自controlfile
從上面的查詢看出來controlfile和datafile中記錄的checkpoint_change#都是1955692
,而且controlfile中記錄的redo的checkpoint_change#也是1955692;但是再來看看redo中記錄的
checkpoint_change#又是多少呢?
我發現redo header上並不會記錄checkpoint_change#,這一點大家可以驗證,當然
當checkpoint發生時很多doc上都提到會把當前的scn更新到controlfile和datafile header上,
並沒有提到會更新再redo的頭上。
SQL> alter session set events 'immediate trace name REDOHDR level 12';

會話已更改。

SQL>
從下面的trace file中我們知道大致判斷LOG FILE #1(#2,#3)這一段的資訊
和controlfile中記錄的一致,我在這裡認定LOG FILE #1(#2,#3)這段資訊是來自controlfile中:從seq(sequence#)就可以判斷出來:0x0000004a,0x0000004c,0x0000004b
分別對應10進位制的74,76,75,而且LOG FILE #2的Next scn: 0xffff.ffffffff,說明它表示是當前redo,這些內容都和controlfile中記錄的完全一致;
但是從 FILE HEADER:這一段開始發現它的內容才是真真來自redo:
因為LOG FILE #1(#2,#3)對應的Seq#分別是: 0000000080,0000000079,0000000081
而且LOG FILE #3的Next scn: 0xffff.ffffffff,說明它表示是當前redo
那麼在redo的header上是否記錄controlfile的資訊呢,應該不記錄,這裡是這條命令:
alter session set events 'immediate trace name REDOHDR level 12';執行時要
從controlfile裡讀取redo的路徑以及一些相關資訊(就是LOG FILE #1(#2,#3)這一段)從而再到redo的header上真真
讀取redo的內容。由於controlfile中記錄的redo的資訊和redo header上記錄的資訊不符,所以開啟db時出現了上面的提示:
"ORA-00314: 日誌 1 (用於執行緒 1) 要求的序號  與  不匹配
ORA-00312: 聯機日誌 1 執行緒 1:
'E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO01.LOG'"

trace file的資訊如下:
--==================================
LOG FILE #1:
  (name #2) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO01.LOG
Thread 1 redo log links: forward: 2 backward: 0
siz: 0x2000 seq: 0x0000004a hws: 0x4 bsz: 512 nab: 0x4eb flg: 0x1 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.001d6386
Low scn: 0x0000.001d65ef 09/30/2008 23:04:54
Next scn: 0x0000.001db8fd 10/01/2008 12:59:45
FILE HEADER:
        Compatibility Vsn = 169869568=0xa200100
        Db ID=1963034992=0x75018970, Db Name='TEST'
        Activation ID=1964389871=0x751635ef
        Control Seq=3855=0xf0f, File size=8192=0x2000
        File Number=1, Blksiz=512, File Type=2 LOG
descrip:"Thread 0001, Seq# 0000000080, SCN 0x0000001def16-0x0000001e03f0"
thread: 1 nab: 0x1ffd seq: 0x00000050 hws: 0x2 eot: 0 dis: 0
reset logs count: 0x27b6a1c6 scn: 0x0000.0015dd61
Low scn: 0x0000.001def16 10/01/2008 17:16:54
Next scn: 0x0000.001e03f0 10/01/2008 19:00:41
Enabled scn: 0x0000.0015dd61 09/24/2008 13:53:10
Thread closed scn: 0x0000.001def16 10/01/2008 17:16:54
Disk cksum: 0x2a74 Calc cksum: 0x2a74
Terminal Recovery Stop scn: 0x0000.00000000
Terminal Recovery Stamp  01/01/1988 00:00:00
Most recent redo scn: 0x0000.00000000
Largest LWN: 315 blocks
Miscellaneous flags: 0x0
Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000
LOG FILE #2:
  (name #3) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO02.LOG
Thread 1 redo log links: forward: 3 backward: 1
siz: 0x2000 seq: 0x0000004c hws: 0x2 bsz: 512 nab: 0x19da flg: 0x8 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.001db8fd
Low scn: 0x0000.001dc8f1 10/01/2008 14:17:00
Next scn: 0xffff.ffffffff 01/01/1988 00:00:00
FILE HEADER:
        Compatibility Vsn = 169869568=0xa200100
        Db ID=1963034992=0x75018970, Db Name='TEST'
        Activation ID=1964389871=0x751635ef
        Control Seq=3850=0xf0a, File size=8192=0x2000
        File Number=2, Blksiz=512, File Type=2 LOG
descrip:"Thread 0001, Seq# 0000000079, SCN 0x0000001dda80-0x0000001def16"
thread: 1 nab: 0x1ffd seq: 0x0000004f hws: 0x2 eot: 0 dis: 0
reset logs count: 0x27b6a1c6 scn: 0x0000.0015dd61
Low scn: 0x0000.001dda80 10/01/2008 16:35:11
Next scn: 0x0000.001def16 10/01/2008 17:16:54
Enabled scn: 0x0000.0015dd61 09/24/2008 13:53:10
Thread closed scn: 0x0000.001dda80 10/01/2008 16:35:11
Disk cksum: 0xe55a Calc cksum: 0xe55a
Terminal Recovery Stop scn: 0x0000.00000000
Terminal Recovery Stamp  01/01/1988 00:00:00
Most recent redo scn: 0x0000.00000000
Largest LWN: 227 blocks
Miscellaneous flags: 0x0
Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000
LOG FILE #3:
  (name #4) E:\ORACLE\PRODUCT\10.2.0\ORADATA\TEST\REDO03.LOG
Thread 1 redo log links: forward: 0 backward: 2
siz: 0x2000 seq: 0x0000004b hws: 0x3 bsz: 512 nab: 0x1ffd flg: 0x1 dup: 1
Archive links: fwrd: 0 back: 0 Prev scn: 0x0000.001d65ef
Low scn: 0x0000.001db8fd 10/01/2008 12:59:45
Next scn: 0x0000.001dc8f1 10/01/2008 14:17:00
FILE HEADER:
        Compatibility Vsn = 169869568=0xa200100
        Db ID=1963034992=0x75018970, Db Name='TEST'
        Activation ID=1964389871=0x751635ef
        Control Seq=3859=0xf13, File size=8192=0x2000
        File Number=3, Blksiz=512, File Type=2 LOG
descrip:"Thread 0001, Seq# 0000000081, SCN 0x0000001e03f0-0xffffffffffff"
thread: 1 nab: 0x501 seq: 0x00000051 hws: 0x2 eot: 1 dis: 0
reset logs count: 0x27b6a1c6 scn: 0x0000.0015dd61
Low scn: 0x0000.001e03f0 10/01/2008 19:00:41
Next scn: 0xffff.ffffffff 01/01/1988 00:00:00
Enabled scn: 0x0000.0015dd61 09/24/2008 13:53:10
Thread closed scn: 0x0000.001e0609 10/01/2008 19:06:21
Disk cksum: 0x9c26 Calc cksum: 0x9c26
Terminal Recovery Stop scn: 0x0000.00000000
Terminal Recovery Stamp  01/01/1988 00:00:00
Most recent redo scn: 0x0000.00000000
Largest LWN: 219 blocks
Miscellaneous flags: 0x0
Thread internal enable indicator: thr: 0, seq: 0 scn: 0x0000.00000000
--=============================================
下面恢復一下db:
SQL> recover database using backup controlfile;
ORA-00279: 更改 1955692 (在 10/01/2008 16:17:24 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

76_%U_.ARC
ORA-00280: 更改 1955692 (用於執行緒 1) 在序列 #76 中


指定日誌: {=suggested | filename | AUTO | CANCEL}
auto
ORA-00279: 更改 1956233 (在 10/01/2008 16:27:12 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

77_%U_.ARC
ORA-00280: 更改 1956233 (用於執行緒 1) 在序列 #77 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_76_4G6F313F_.ARC'


ORA-00279: 更改 1956324 (在 10/01/2008 16:30:40 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

78_%U_.ARC
ORA-00280: 更改 1956324 (用於執行緒 1) 在序列 #78 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_77_4G6F9JSW_.ARC'


ORA-00279: 更改 1956480 (在 10/01/2008 16:35:11 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

79_%U_.ARC
ORA-00280: 更改 1956480 (用於執行緒 1) 在序列 #79 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_78_4G6FL06C_.ARC'


ORA-00279: 更改 1961750 (在 10/01/2008 17:16:54 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

80_%U_.ARC
ORA-00280: 更改 1961750 (用於執行緒 1) 在序列 #80 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_79_4G6J06PY_.ARC'


ORA-00279: 更改 1967088 (在 10/01/2008 19:00:41 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

81_%U_.ARC
ORA-00280: 更改 1967088 (用於執行緒 1) 在序列 #81 中
ORA-00278: 此恢復不再需要日誌檔案
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_80_4G6P2T6T_.ARC'


ORA-00308: 無法開啟歸檔日誌
'E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1

_81_%U_.ARC'
ORA-27041: 無法開啟檔案
OSD-04002: 無法開啟檔案
O/S-Error: (OS 2) 系統找不到指定的檔案。


SQL>
SQL> select hxfil,fhrba_seq,fhrba_bno,fhrba_bof from  x$kcvfh;

     HXFIL  FHRBA_SEQ  FHRBA_BNO  FHRBA_BOF
---------- ---------- ---------- ----------
         1         81          2          0
         2         81          2          0
         3         81          2          0
         4         81          2          0
SQL> select sequence#,last_redo_sequence# from v$thread;

SEQUENCE# LAST_REDO_SEQUENCE#
---------- -------------------
        76                  76

SQL>
--目前datafile header上的sequence#是81,也就是恢復db接下來需要的redo sequence#是81,也就是當前redo:group 3;
而controlfile中記錄的是76,因此當controlfile不是最新時,此時恢復db是無法自動應用redo,就是這個道理,
需要我們挨個輸入redo來嘗試,當然前面已經對redo的header進行了dump,我們
知道81的redo是group 3,接著恢復,並且輸入group 3對應的redo的路徑和名稱

SQL> recover database using backup controlfile;
ORA-00279: 更改 1967088 (在 10/01/2008 19:00:41 生成) 對於執行緒 1 是必需的
ORA-00289: 建議:
E:\ORACLE\PRODUCT\10.2.0\FLASH_RECOVERY_AREA\TEST\ARCHIVELOG\2008_10_01\O1_MF_1_

81_%U_.ARC
ORA-00280: 更改 1967088 (用於執行緒 1) 在序列 #81 中


指定日誌: {=suggested | filename | AUTO | CANCEL}
E:\oracle\product\10.2.0\oradata\test\redo03.log
已應用的日誌。
完成介質恢復。
SQL> alter database open  resetlogs;

資料庫已更改。



文章出處:http://www.itpub.net/thread-1065138-1-1.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-664520/,如需轉載,請註明出處,否則將追究法律責任。

相關文章