14.5 用Bak文件恢复到故障点的奥秘
如果数据库被损坏,我们就只能利用备份集文件(通常扩展名为BAK)来恢复数据库,如果备份集中包含了尾日志备份,我们同样能将数据库恢复到故障点。
前面我们已经介绍了使用restore headeronly命令可以查看备份集文件的头部信息。这里的信息和msdb系统数据库中保存的信息是一致的。
区别在于在删除数据库时,我们可以选择是否同时删除msdb系统数据库中的备份信息,而备份集文件的备份信息是存储在其头部的,不会随着msdb系统数据库的备份信息的删除而被删除。
14.5.1 发现的问题
在Management Studio中选择还原数据库,选择从设备还原,设置设备为bak文件,出现如图14-27所示的【常规】选项卡。
图14-27 【常规】选项卡
然而,令我们吃惊的是,尽管备份集中有3个日志备份(2个日志备份+1个尾日志备份),而且这3个日志备份的LSN是前后续接的,但是在图14-26中我们只能发现2个日志备份的序列,尾日志备份序列不可见,经过笔者的反复实验,这个问题始终存在。
因为不能应用尾日志备份,所以肯定不能将数据库恢复到故障点!那么是不是尾日志备份就不能使用了呢?
14.5.2 解决的办法
经过若干次反复的实验,发现始终不能在图形化操作中解决这个问题。尽管尾日志的备份序列和前面的日志备份序列首尾连接,但是在图形化界面中确实无法选择。
作者将目光投向了RESTORE DATABASE和RESTORE LOG语句上。最后成功解决了这个问题。
1.成功的实例
最后成功完成尾日志恢复的语句实例如下。
RESTORE DATABASE [db_test] FROM DISK = N'C:\test2.bak'
WITH FILE = 1,
NORECOVERY,
NOUNLOAD,
REPLACE,
STATS = 10
GO
RESTORE LOG [db_test] FROM DISK = N'C:\test2.bak'
WITH FILE = 2,
NORECOVERY,
NOUNLOAD,
STATS = 10
GO
RESTORE LOG [db_test] FROM DISK = N'C:\test2.bak'
WITH FILE = 3,
NORECOVERY,
NOUNLOAD,
STATS = 10
GO
RESTORE LOG [db_test] FROM DISK = N'C:\test2.bak'
WITH FILE = 4,
NOUNLOAD,
STATS = 10
GO
光盘代码:\代码\1407.sql。
2.解决思路
下面的语句为恢复尾日志的语句。
RESTORE LOG [db_test] FROM DISK = N'C:\test2.bak'
WITH FILE = 4,
NOUNLOAD,
STATS = 10
可以看出,上述恢复尾日志的语句和恢复日志序列语句是不同的。
RESTORE LOG [db_test] FROM DISK = N'C:\test.bak'
WITH FILE = 3,
NORECOVERY,
NOUNLOAD,
STATS = 10
最本质的不同,是尾日志恢复少了一个参数NORECOVERY。
3.NORECOVERY参数的奥秘
那么,为什么NORECOVERY参数就可以恢复尾日志呢?
RECOVERY参数指示还原操作回滚任何未提交的事务。在恢复进程后即可随时使用数据库。如果既没有指定NORECOVERY和RECOVERY,也没有指定STANDBY,则默认为RECOVERY。
NORECOVERY参数指示还原操作不回滚任何未提交的事务。如果稍后必须应用另一个事务日志,则应指定NORECOVERY或STANDBY选项。使用NORECOVERY选项执行脱机还原操作时,数据库将无法使用。
4.使用方法
还原数据库备份和一个或多个事务日志时,或者需要多个RESTORE语句(例如还原一个完整的数据库备份并随后还原一个完整的差异备份)时,RESTORE需要对所有语句使用WITH NORECOVERY选项,但最后的RESTORE语句除外。
14.5.3 验证是否恢复到故障点
(1)执行1407.sql,执行结果如图14-28所示。
图14-28 执行恢复
(2)执行dbcc log语句,查询恢复后的数据库的日志情况如图14-29所示。
— 第1条日志记录的Current LSN:0000001e:00000013:0001。
— 最后1条日志记录的Current LSN:0000001e:00000064:000a。
图14-29 恢复后的数据库日志
在图14-23中,我们知道发生尾日志备份后的数据库日志的最后一条日志记录的Cureent LSN为:0000001e:00000050:0001。
由于恢复后的日志记录的LSN(0000001e:00000144:000a)>故障点时的日志记录的LSN(0000001e:00000050:0001),所以我们得出结论,我们的恢复操作确实将数据库恢复到了故障点。多余出来的LSN是由于备份和恢复操作产生的日志记录。
(3)理论上我们已经验证了,那么,按照我们的实验数据,故障点时的最后一条日志记录应该出现在恢复后的日志中。
接下来我们执行dbcc log语句查询日志记录,发现该日志记录果然存在于日志记录中,如图14-30所示。
图14-30 恢复后的数据库日志
(4)我们还可以通过执行查询数据库中特定表的数据来判断是否恢复到了故障点。
执行下列语句,查询结果显示有799条数据,正是我们模拟故障点发生时的数据库中的数据。
select count(*) from db_test.dbo.t_clusterindextest