天天看點

Oracle之不完全恢複

整理自《Oracle database 11g RMAN 備份與恢複》

001 概述

    顧名思義,不完全恢複就是指不完全的資料庫恢複。不完全恢複與完全恢複在許多方面是相同的,它們基本的指令集相同,但不完全恢複添加了一些其它指令。引起不完全恢複的原因有很多,如丢失了聯機重做日志或歸檔的重做日志,或者出現重大的使用者錯誤。<b>不完全恢複會影響整個資料庫</b>;換句話說,不能隻對資料庫的一部分執行不完全恢複操作,因為這會使資料庫的一部分具有與這個資料庫其餘部分不同的系統更改号(SCN)或時間點。

    不完全恢複影響的是整個資料庫,這一點是非常重要的概念。一個典型的例子是:使用者錯誤地删除了表空間中的一個表,并且沒有備份這個表。要求将這個表空間恢複發哦該使用者執行删除操作之前的時間點。

    初級DBA起初可能會認為隻需要還原損壞表空間的資料檔案并将這些資料檔案恢複到執行删除操作之前的時間點。這些操作看上去非常符合邏輯,實際上,這正是邏輯備份的操作。是以,初級DBA還原了資料檔案,并将表空間恢複到删除操作之前的時間點,但當其嘗試打開資料庫時,RMAN會給出下面的資訊:

ERROR at line 1:

ORA-01113:file 3 needs media revoery

ORA-01110:data file 3:'/u01/app/oracle/oradata/ORCL/INDEX01.DBF'

    在這個示例中,Oracle告訴使用者恢複資料檔案是成功的,但是這些資料檔案恢複得不夠,與資料庫的其他部分不一緻!是以,不完全恢複并非所有災難的解決方案,它隻是某些災難的解決方案。如果需要某種形式的不一緻恢複(将一些資料庫資料還原至與資料庫剩餘部分不同的時間點),則有表空間時間點恢複,或者閃回技術。

    然而,如果需要将整個資料庫還原到閃回資料庫無法到達的過去的某個時間點,則需要使用不完全恢複。當執行資料庫不完全恢複時,需要使用Resetlogs指令,因為差不多所有的不完全恢複情況都要用到Resetlogs指令。

    我們将在下面介紹該指令,随後還要讨論實際的不完全恢複方法,這些方法包括基于時間、SCN、日志序列或取消的恢複。

002 使用Resetlogs指令

    在不完全恢複期間,通常需要使用Resetlogs指令打開資料庫,這是因為我們要從已經建立的現有重做流中脫離出來,并且需要向Oracle說明這種情況。Resetlogs指令表示一個資料庫邏輯生存周期的結束和另一個資料庫邏輯生存周期的開始。資料庫的邏輯生存期也稱為一個對應物(incarnation)。每次使用Resetlogs指令都會建立一個新的資料庫對應物,這對于恢複操作來說非常重要,我們将在後面讨論這個問題。

    每次使用Resetlogs指令時,SCN計數器不會被重置,不過Oracle會重置其它計數器(如日志序列号),同時還會重置聯機重做日志的内容(如果有必要還可以重新建立聯機重做日志)。

    從Oracle database 10g開始,簡化了通過Resetlogs指令進行的恢複。在歸檔的重做日志名中添加了一個新的替換字元串(%r),該字元串表示Resetlogs ID号。在log_archive_dest_format參數字元串中包括%r時,歸檔的重做日志名在每個Resetlogs指令中保持唯一。這種改動以及其他的内部Oracle資料庫改動使Oracle可以很容易地通過給定的Resetlogs操作恢複資料庫。是以,可以很容易地在執行Resetlogs操作後立刻備份資料庫。然而,我們仍然認為在任何不完全恢複後備份資料庫是很好的想法。

    注意:在以前版本的RMAN中,需要重新建立所有的臨時表空間臨時檔案。Oracle database 10g和以後的版本中則不需要這種操作,RMAN在恢複資料庫過程期間會建立這些資料檔案,甚至在不完全恢複期間也是如此!

003 建立恢複點

    使用RMAN執行不完全恢複操作時需要完成的一個工作是建立恢複目标。<b>恢複目标是恢複程序的終點,通常我們基于一個時間點、一個指定的SCN或一個日志序列号來辨別它。</b>我們可以使用許多不同的方法建立恢複目标。首先,可以在run代碼塊中使用set指令與until time、until SCN或until sequence參數,下面的示例使用set until time指令建立了一個為2016年1月19日下午3點的恢複目标:

    run

    {

    set until time "to_date('01/19/16 15:00:00','mm/dd/yy hh24:mi:ss')";

    restore database;

    recover database;

    alter database open resetlogs;

    }

    執行這條指令時,RMAN會查找與恢複目标時間最近(并非恢複目标時間本身,也不能是恢複目标之後的時間)的備份集,并且從這個備份集中還原資料庫。如果資料庫置于noarchivelog模式中,恢複操作會在備份集的時間點停止;否則在執行recover指令期間,Oracle會在所定義的恢複目标(不包含恢複目标本身)上應用歸檔的重做日志(以及需要應用的任何增量備份)。

    注意:如果嘗試恢複到特定備份的完成點,則必須恢複到備份集中檔案的ckp SCN或ckp time,在不同備份集的RMAN的list指令中列出了這些内容(例如 list backup)。有時候使用備份的ckp time并不夠,還可能導緻ORA-1152錯誤。

    也可以選擇在restore和recover指令中直接使用until time、until SCN或until sequence指令,這樣就避免使用run代碼塊(我們傾向于使用這種方法)。下面是在還原和恢複資料庫時所使用的until time指令示例:

    --we assume that your control file is intact

    startup mount;

    restore database until time

    “to_date('01/19/16 13:00:00','MM/DD/YY HH24:MI:SS')";

    recover database until time

    "to_date('01/19/16 13:00:00','MM/DD/YY HH24:MI:SS')";

004 基于時間的恢複

    003中給出了一些基于時間的恢複示例。這種恢複類型允許使用者将資料庫恢複到與指定時間一緻的狀态。當然,如果不存在能将資料庫還原到使用者請求的時間的有效備份或歸檔重做日志,Oracle就會生成如下所示的錯誤:

Oracle之不完全恢複

    最後需要強調的是必須具備在我們所指定的恢複時間之前生成的資料庫備份,此外還需要所有的歸檔重做日志。利用list和report指令,我們可以确定RMAN還原資料庫可以使用的備份。

005 基于SCN的恢複

    Oracle允許使用者将資料庫恢複到指定的SCN。實際上,這并不是一種常用的恢複方法,不過最好了解一下它的用法。下面是一個将資料庫還原到指定SCN的示例:

    假定控制檔案完整:

    startup mount;

    restore database until SCN 10000;

    recover database until SCN 10000;

    在這個示例中,我們将資料庫還原到SCN 10000(但是不包含這個SCN)。

006 基于日志序列的恢複

    RMAN允許使用者将資料庫恢複到指定序列号的歸檔重做日志。如果歸檔的重做日志中存在間隙,使用這種恢複方法就非常友善。間隙通常意味着我們隻能将資料庫還原到間隙的開始點。下面是一個在RMAN中執行基于日志序列的恢複操作的示例:

    假定控制檔案是完整的:

    restore database until sequence 100 thread 1;

    recover database until sequence 100 thread 1;

    在這個示例中,我們将資料庫還原到日志序列為100(但是不包含這個日志序列)的資料庫。

007 基于删除的恢複

    RMAN不支援類似于sqlplus所做的基于删除的恢複(雖然基于删除的恢複在一定程度上非常類似于基于日志序列的恢複),而是希望使用者了解恢複到的時間、SCN或日志序列号,因為這樣非常有意義。如果需要執行基于删除的恢複,則需要從RMAN中将資料檔案還原到恢複時間之前的一些時間點。我們需要手動析取基于删除的恢複所需的歸檔重做日志,然後需要從sqlplus用戶端中執行資料庫的基于删除的恢複。

008 使用還原點恢複

    可以利用還原點定義資料庫還原到的時間點。基于還原點還原資料庫,隻包含restore和recover指令的to restore point子句,如下所示:

    restore database until restore point tango_one;

    recover database until restore point tango_one;

    也可以使用run代碼塊和set until restore point指令建立還原點,如下所示:

    run {

    set restore point tango_one;

    restore databsae tango_one;

    recover database tango_one;