恢复路径

如果您使用差异或日志备份并且通过下列方式之一将数据库恢复到以前的时间点,则很有必要理解恢复路径:

  • 执行时点还原

  • 执行恢复而不先还原所有日志备份或最新的差异备份。

如果将数据库恢复到更早的恢复点并从该点开始使用数据库,会生成一个新的恢复路径。“恢复路径”是指通过正常的数据库使用或特定的数据和日志还原将数据库恢复到特定时间点的数据和日志备份的序列。恢复路径由一组不同的转换(随着时间的变化对数据库进行演变并保持一致性)组成。下图说明了恢复点与其生成的恢复路径之间的关系。

恢复点和最终恢复路径

下列情况会创建新的恢复路径,因为数据库未还原到“结束时间”。此后,会出现使数据库进入两个或两个以上恢复路径的备份,它们都使用同一组 LSN。

  • 在不使用任何其他备份类型的情况下,还原完整数据库备份并恢复数据库。

  • 将数据库恢复到非最新的差异备份的结尾处。

  • 不应用现有的事务日志备份还原完整数据库备份和差异数据库备份并恢复数据库。

  • 将数据库恢复到非最新的事务日志备份的结尾处。

  • 将数据库恢复到特定时间或事务日志备份中的某个标记事务处。

通常,如果某恢复点导致事务回滚,则该恢复点将启动一个新的恢复路径。预先存在的备份现在可能具有比此恢复点的日志序列号 (LSN) 更大的 LSN。这些备份中的 LSN 存在于由当前恢复操作创建的新分支以外的恢复分支中。

最佳方法 若要避免创建具有多个恢复分叉的恢复路径,请在恢复数据库之后尽快执行一组完整的数据备份。此方法可保证对单个恢复分支执行所有备份。若要对此进行验证,可以在备份数据后查看 backupset 表中的 last_recovery_fork_guid 列或 RESTORE HEADERONLY 结果集。

恢复路径示例

最初,数据库的所有备份构成一个恢复路径,如下图所示。在该图中,恢复路径包含一个数据库备份(时间为 t1)和三个日志备份(时间分别为 t2、t3 和 t4)。

原始恢复路径

下图显示了将数据库恢复到一个旧时点时所获得的一个恢复分叉。备份 t4 的问题导致数据库管理员在 t3 日志备份的末尾恢复数据库。该还原操作导致了一个恢复分叉。在时间 t5 处,一个新的日志备份启动了一个新的恢复分支,即恢复分支 2。

创建第二个恢复分支

注意注意

t5 日志备份包含将此备份连接至恢复分支 1 上的 t3 日志备份的恢复分叉元数据。有关恢复分叉元数据的信息,请参阅本主题后面的“管理恢复分叉”部分。

上图中的示例创建了一个新的恢复路径,如下图所示。新恢复路径包含恢复分支 1 上的部分备份(t1 到 t3)以及恢复分支 2 上的所有日志备份(t5 到 t9)。从此恢复路径的角度看,日志备份 t4 已过时。

新的恢复路径

时点还原之后的下一个备份始终会导致恢复分叉。在下图中,在 t4 日志备份的中间完成了一个时点还原。将数据库恢复到该时点导致了一个恢复分叉。然后,在时间 t5 处为恢复的数据库创建了一个日志备份,从而建立了恢复分支 2 并创建了一个新的恢复路径。新分支上的第一个日志备份 t5 所包含的第一个 LSN 与日志备份 t3 相同,并将替换后者。因此,t3 和 t4 备份在新的恢复路径上均已过时。

时点还原之后的新恢复路径

若要沿此新恢复路径还原备份,则其还原顺序为:t1、t2 和 t5。将来在恢复分支 2 上做备份时,这些备份将纳入该新恢复路径中。

还原并沿旧路径前滚

通常,当存在多个恢复路径时,其中最新的恢复路径将是还原数据库的首选路径。建议您不要使用旧的恢复路径。但是,如有必要,可以按照在创建当前恢复路径之前所做的备份顺序,沿着旧的恢复路径前滚。例如,可以使用在时点恢复之前所做的备份来到达旧路径上后面的各个时点。

例如,根据上图中创建的备份,在创建日志备份 t5 之后,仍可以从 t1 处所做的完整数据库备份还原到日志备份 t4 的末尾。这是在旧恢复路径上进行的。

还原并从旧路径前滚到新路径

SQL Server 数据库引擎禁止在一个还原顺序中使用来自不同路径的备份(即试图沿不同恢复路径前滚)。此限制使得数据库在恢复之后仍能保持一致。

若要还原并沿新恢复路径前滚,请为恢复点之前和之后的备份构造不同的还原顺序:

  1. 还原在引入新恢复路径的恢复之前所做的备份。排除包含恢复点的备份。

  2. 通过还原在创建恢复路径之后所做的备份,沿新恢复路径前滚。

管理恢复分叉

“恢复分支”是共享同一 GUID 的一组 LSN。恢复路径描述从“起点” (LSN,GUID) 到“终点” (LSN,GUID) 的一组 LSN。恢复路径中的 LSN 可以从起点到终点遍历一个或多个恢复分支。创建数据库并用 RESTORE WITH RECOVERY 生成恢复分叉之后,会生成新的恢复分支。

“恢复分叉”指每次执行 RESTORE WITH RECOVERY 时,开始新的恢复分支的点 (LSN,GUID)。每个恢复分叉都确定了恢复分支之间的父子关系。

恢复数据库会将整个数据库状态(包括下一个 LSN)设置到恢复点。然后从 fork_point_lsn 开始重用 LSN。因此,在构造还原顺序时,必须按恢复分叉和 LSN 将备份链接起来,因为同一 LSN 可能存在于多个分叉中。下图说明了如何重用 LSN。它显示了在不同的恢复分叉中如何重用 LSN。图中的绿框表示使用相同 LSN 的两个备份。

在不同的恢复分支中如何重用 LSN

如果还原顺序必须包含遍历恢复分叉的备份,则在构造还原顺序时必须使所用的备份沿正确的恢复路径到达恢复点。因此,备份将包括第一个恢复分叉 GUID 和最后一个恢复分叉 GUID。

这些 GUID 连同其他与跟踪恢复路径相关的元数据都存储在 backupset 历史记录表中,也可以由 RESTORE HEADERONLY 语句返回。下表汇总了与构造遍历某个恢复分叉的还原顺序相关的元数据值。请注意,这些值的列名称对于历史记录表和 RESTORE HEADERONLY 语句的结果集是不同的:

LSN

说明

backupset 列名称

RESTORE HEADERONLY 列名称

第一个恢复分叉 GUID

起始恢复分叉的 ID。

first_recovery_fork_guid

FirstRecoveryForkID

最后一个恢复分叉 GUID

末尾恢复分叉的 ID。

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 按文件逐一确定差异基准。