復原路徑

如果使用差異或記錄備份,而且透過下列兩種方法之一,將資料庫復原至先前的時間點,瞭解復原路徑就很重要:

  • 執行時間點還原

  • 不先還原所有記錄備份或大部分最近的差異備份,就執行復原。

如果將資料庫復原到較早的復原點,並且從該復原點開始使用資料庫,則會產生新的復原路徑。「復原路徑」是資料與記錄備份的順序,以一般資料庫使用方式或特定的資料與記錄還原方式,將資料庫帶回到特定的時間點。復原路徑包含唯一的一組特定轉換,使資料庫隨時間而變化,同時又能維護資料庫的一致性。下圖說明復原點與所產生復原路徑之間的關係。

復原點和產生的復原路徑

下列情況會產生新的復原路徑,因為資料庫未還原至「結束時間」。之後,有備份存在,可以帶領資料庫循兩個或多個復原路徑還原,全部都使用相同範圍的 LSN。

  • 還原完整資料庫備份並復原資料庫,但不使用其他任何類型的備份。

  • 將資料庫復原到某個差異備份的結尾,而不是最近一次的差異備份。

  • 還原完整資料庫備份與差異資料庫備份並復原資料庫,而不套用現有的交易記錄備份。

  • 將資料庫復原到某個交易記錄備份的結尾,而不是最近一次的交易記錄備份。

  • 將資料庫復原到交易記錄備份中特定的時間或標示的交易。

一般而言,如果復原點造成交易復原,復原點會開始新的復原路徑。預先存在的備份現在可能有大於此復原點之 LSN 的記錄順序編號 (LSN)。這些備份中的 LSN 存在於不同的復原分支上,來自目前復原作業所建立的新分支。

最佳作法:若要避免產生有多個復原分岔的復原路徑,請在復原資料庫之後,儘快執行一組完整的資料備份。這種作法保證所有備份都是取自單一復原分支。若要確認,可以在備份資料之後查看 backupset 資料表或 RESTORE HEADERONLY 結果集中的 last_recovery_fork_guid 資料行。

復原路徑的範例

一開始,資料庫的所有備份會形成單一復原路徑,如下圖所示。在此圖中,復原路徑包含資料庫備份 (於 t1 時間取得) 以及三個記錄備份 (於 t2、t3 和 t4 時間取得)。

原始復原路徑

下圖顯示將資料庫復原至舊的時間點所產生的復原分岔。備份 t4 的問題會造成資料庫管理員在 t3 記錄備份結尾復原資料庫。這樣的還原會造成復原分岔。在時間 t5,新的記錄備份會啟動新的復原分支 (復原分支 2)。

建立第二個復原分支

[!附註]

t5 記錄備份包含了復原分岔中繼資料,可將此備份連接到復原分支 1 上的 t3 記錄備份。如需有關復原分岔中繼資料的詳細資訊,請參閱本主題稍後的「管理復原分岔」。

上圖顯示的範例會建立新的復原路徑,這將顯示於下圖中。新的復原路徑包括復原分支 1 上的某些備份 (t1 到 t3) 及復原分支 2 上的每一個記錄備份 (t5 到 t9)。從此復原路徑的觀點來看,記錄備份 t4 已過時。

新復原路徑

在時間點還原之後,下一個備份一定會造成復原分岔。在下圖中,時間點還原是透過 t4 記錄備份而在中途完成。將資料庫復原至該時間點會造成復原分岔。然後,會在時間 t5 於復原的資料庫上建立記錄備份,建立復原分支 2 和建立新的復原路徑。新分支上的第一個記錄備份 t5 包含了與記錄備份 t3 相同的第一個 LSN,並會取代它。因此,t3 和 t4 備份在新的復原路徑上都已過時。

時間點還原後的新復原路徑

若要在這個新的復原路徑上還原備份,還原順序如下:t1、t2 和 t5。當未來在復原分支 2 上進行備份時,會將其併入新的復原路徑。

還原並沿著舊路徑向前復原

一般來說,當有多個復原路徑存在時,其中最新的復原路徑會是還原資料庫的優先路徑。我們建議您避免使用舊的復原路徑。但是必要時,您可以遵循建立目前復原路徑之前所採取的備份順序,沿著舊的復原路徑向前復原。例如,您可以使用時間點復原之前的備份,沿著舊路徑到達之後的時間點。

例如,根據先前圖中建立的備份,在建立記錄備份 t5 之後,仍然可以從 t1 進行的完整資料庫備份還原至記錄備份 t4 的結尾。這是位於舊的復原路徑上。

還原並從舊路徑向前復原到新路徑

SQL Server Database Engine 會避免讓還原順序使用不是同時產生的備份 (亦即,嘗試沿著不同的復原路徑向前復原)。此限制可以讓資料庫在復原之後維持一致性。

若要還原並沿著新的復原路徑向前復原,請為復原點之前的備份與復原點之後的備份建構不同的還原順序:

  1. 還原取自導入新復原路徑之復原以前的備份。排除包含復原點的備份。

  2. 還原取自復原路徑建立以來的備份,沿著新復原路徑向前復原。

管理復原分岔

復原分支是共用相同 GUID 之 LSN 的範圍。復原路徑描述從起點 (LSN,GUID) 到終點 (LSN,GUID) 的 LSN 範圍。復原路徑中的 LSN 範圍從開始到結束可能會跨越一或多個復原分支。當資料庫建立時以及當 RESTORE WITH RECOVERY 產生復原分岔時,就會產生新的復原分支。

「復原分岔」(Recovery Fork) 是每次執行 RESTORE WITH RECOVERY 時,新復原分支的起始點 (LSN,GUID)。每一個復原分岔決定復原分支之間的父子關聯性。

復原資料庫會將整個資料庫的狀態 (包括下一個 LSN) 設定到復原點。然後 LSN 會從 fork_point_lsn 開始重複使用。所以建構還原順序時,備份必須與復原分岔以及 LSN 連結,因為可能會有一個以上的分岔有相同的 LSN。下圖說明 LSN 重新使用情形。示範如何在不同的復原分岔中重複使用 LSN圖中的綠色方塊表示使用相同 LSN 的兩個備份。

如何在不同的復原分岔中重複使用 LSN

如果還原順序必須納入跨越復原分岔的備份,就必須建構還原順序,以便使用的備份依照正確的復原路徑回到復原點。基於這個目的,備份包含了第一個復原分岔 GUID 和最後一個復原分岔 GUID。

這些 GUID (連同與追蹤復原路徑有關的其他中繼資料) 都會儲存在 backupset 記錄資料表中,而且也會由 RESTORE HEADERONLY 陳述式傳回。下表摘要列出與建構可周遊復原分岔之還原順序有關的中繼資料值。請注意,對於記錄資料表及 RESTORE HEADERONLY 陳述式的結果集而言,這些值的資料行名稱是不同的:

LSN

描述

備份組資料行名稱

RESTORE HEADERONLY 資料行名稱

第一個復原分岔 GUID

起始復原分岔的識別碼。

first_recovery_fork_guid

FirstRecoveryForkID

最後一個復原分岔 GUID

結尾復原分岔的識別碼。

last_recovery_fork_guid

RecoveryForkID

第一個 LSN

備份組中第一個或最舊記錄的記錄序號。

first_lsn

FirstLSN

最後一個 LSN

備份組之後下一個記錄的記錄序號。

last_lsn

LastLSN

分岔點 LSN

如果第一個復原點 GUID 不等於 (≠) 最後一個復原點 GUID,則表示分岔點的記錄序號。否則,備份中不會發生任何復原分岔,而且分岔點 LSN 為 NULL。

fork_point_lsn

ForkPointLSN

差異基底 GUID

如果是單一基底差異備份,這個值就是差異基底的唯一識別碼。

如果是多重基底差異備份,這個值就是 NULL,差異基底必須取決於檔案層級。如需詳細資訊,請參閱<backupfile (Transact-SQL)>。

如果是非差異備份類型,這個值就是 NULL。

differential_base_guid

DifferentialBaseGUID

此討論的其餘部分只會使用 backupset 記錄資料表中的值名稱。

  • 最後一個復原分岔 GUID 和第一個復原分岔 GUID 是用來連結備份,以確保此順序會遵循正確的分岔。對於要還原之順序中的每個記錄備份,first_recovery_fork_guid 必須與順序中先前備份的 last_recovery_fork_guid 相等。

    first_recovery_fork_guid = last_recovery_fork_guid

  • 也必須連結資料和差異備份。

    若記錄備份同時包含完整資料庫備份或差異資料庫備份的最後一個 LSN 以及分岔點,連結測試會視與分岔點相關的最後一個 LSN 位置而定。

    使用 backupset 值的連結測試如下:

    • last_lsn 小於或等於 fork_point_lsn,則資料或差異備份的 last_recovery_fork_guid 必須等於記錄備份的 first_recovery_fork_guid。下圖說明 last_lsn 小於 fork_point_lsn 的狀況。

      last_lsn 小於 fork_point_lsn

    • last_lsn 大於 fork_point_lsn,則資料或差異備份的 last_recovery_fork_guid 必須等於記錄備份的 last_recovery_fork_guid。下圖說明 last_lsn 大於 fork_point_lsn 的狀況。

      last_lsn 大於 fork_point_lsn

  • 對於差異備份,請使用 backupset.differential_base_guid 找出差異基底。

    如果差異備份有多個基底,backupset.differential_base_guid 是 NULL,則您必須使用 backupfile.differential_base_guid,每個檔案逐一判斷差異基底。