技术开发 频道

SQL Server 2005灾难恢复方法和步骤

  【IT168 技术文档】SQL Server 2005在实现高可用性和灾难恢复方面给我们提供了很多种选择。比技术本身更重要的是拿出适当的程序,这是因为我们要管理不同的灾难恢复方案。我们应该如何拿出程序来管理多种多样的灾难恢复场景呢?

  专家解答

  这一系列文章将探讨不同的灾难恢复场景和涉及你的恢复计划的程序。考虑到你的SQL Server 2005数据库中的灾难恢复选项,你应该包含尽可能多的技术,因为如果灾难发生时你将会有很多种选择来解决这个问题。尽管拥有这些技术被证实是很重要的,但是它也是一个伴随着使整个程序更加有效的过程。在这篇文章里,让我们来看看一个简单的场景,那就是在发生数据库备份的5个小时后,一个用户不小心删除了一张表。从一个数据库备份中恢复意味着失去5小时的数据。而对于大多数的公司来说,比起失去数据,他们更愿意选择失去时间。并且,如果这是一个非常大的数据库,那么将花很长一段时间来恢复和使它联机。在将数据损失控制到最小的前提下,我们将考虑这种情况来建立一个程序方法,以此来尽快地恢复数据库。我们将使用Northwind数据库来显示这个过程。记住在进行以下步骤之前先把Northwind中的数据库恢复模式改成FULL。

  (1) 确保你有一个好的备份

  针对上面的场景,我们假设你有一个每天早上6:00运行的备份,并且没有一个定期创建的数据库快照。你的数据库被配置成使用一个单一的MDF和LDF文件,这个文件对灾难恢复不太适用。让我们在Northwind数据库中创建一个全数据库备份,它将是数据库恢复的起始点。以下是代码:

USE master
  
GO
  
BACKUP DATABASE Northwind
  
TO DISK = N'D:\DBBackup\NorthwindBackup.bak'
  
WITH NAME = N'Full Database Backup', DESCRIPTION = 'Starting point for recovery'
  INIT, STATS
= 10
  
GO

  从Northwind数据库模式中,你很难删除Products, Orders和Customers表,这是因为有其他表比如Order Details表的外码约束限制。但我敢打赌你可以轻易地删除Order Details表。接下来,我们来模拟在大约上午11:00时删除这张表的灾难情景。
 
 DROP TABLE [Order Details]

  (2) 包含发生的问题

  由于这个数据库只有一个单一的MDF和LDF文件,我们不可能做很多操作。我们所能做的就是通过把它设置成有限制的用户模式来使数据库脱机。

USE master
  
GO
  
ALTER DATABASE Northwind
  
SET RESTRICTED_USER
  
WITH ROLLBACK IMMEDIATE
  
GO

  这将很有效地使数据库脱机,停止所有活动的连接。这是分秒必争的时刻,我们需要采取行动。当进行到下面的步骤时,请牢记你的RPO和RTO。

  (3) 备份事务日志

  一个好的数据库管理员应该知道当灾难来临时,首先要做的是备份事务日志 – 假设你的数据库被设置成全数据库备份。这是为了确保在上次备份之后你还保存所有活动的事务。在我们的场景中,由于上次的备份 – 全备份,在这个例子中 – 发生于早上6:00。

BACKUP LOG Northwind
  
TO DISK = N'D:\DBBackup\NorthwindBackupLog.trn'
  
WITH NAME = N'Transaction Log Backup'
  , DESCRIPTION
= 'Getting everything to current point in time.'
  STATS
= 10
  
GO

  (4)还原数据库到一个已知的良好时间点
  
  现在,任何用户意外地删除一张表或者在数据库上造成一些破坏后都不会立即告诉你。有时候,你可能需要自己深入挖掘它,但是这需要花很多时间。由于我们想让数据库尽快地联机,所以我们假设一个众所周知的良好时间点,并且让发掘在稍后的时间里进行。在下面的脚本中,我将选择在我的STOPAT参数中将早上 10:42设置成已知的良好时间点,一次达到展示的目的。

RESTORE DATABASE Northwind
  
FROM DISK = N'D:\DBBackup\NorthwindBackup.bak'
  
WITH NORECOVERY, RESTRICTED_USER
  
GO
  
RESTORE LOG Northwind
  
FROM DISK = N'D:\DBBackup\NorthwindBackupLog.trn'
  
WITH RESTRICTED_USER,
  STOPAT
= '2008-09-23 10:42:44.00', RECOVERY
  
-- use a "known good" point in time
  GO

  虽然我们已经把数据库恢复到一个已知的良好时间点,但是我们并没有知道我们实际上到底失去了多少数据。我们需要找出在执行DROP TABLE语句之前执行最后的一个INSERT语句的准确时间,这样我们才能恢复尽可能多的数据。但是由于我们需要尽可能快地使数据库联机,所以我们不想在数据库上直接做这些。这正证明了接下来的步骤是有价值的。

  你可以通过执行一个针对它的查询来验证删除的表是否已经恢复。

SELECT *
  
FROM Northwind.dbo.[Order Details]
  
GO

   (5)创建一个恢复点的快照

  我们将创建一个还原数据库的数据库快照,以此来做进一步的处理。这个数据库快照将是把数据恢复到执行DROP TABLE语句之前的准确时间的参考。

USE master
  
GO
  
CREATE DATABASE Northwind_RestorePointSnapshot
  
ON
  ( NAME
= N'Northwind'
  FILENAME
= N'D:\DBBackup\NorthwindData_RestorePontSnapshot.snap')
  
AS SNAPSHOT OF [Northwind]
  
GO

  依靠这个表模式,我们可以选择让它保持原状,或者像我们对Order Details 表所做的那样,或者多做一些操作。如果这张表有一个现有IDENTITY栏,我们需要在IDENTITY栏的最大值和需要恢复的行的假设数量之间创建一个间隙。这当然取决于在服务器上发生的事务数目。要确定IDENTITY栏的最大值,你可以执行如下显示的DBCC CHECKIDENT命令:

DBCC CHECKIDENT ('tableName')
 
--Displays the number of rows you have for the restored table  
 GO

  这将返回IDENTITY列的最大值。让我们假设这张表每天的事务数目大约是4000条记录,我们可以在最大值和下一个值之间创建一个间隙。如果IDENTITY列的最大值是25000,我们需要将4000加到这个值中,并且再次执行带有RESEED参数的DBCC CHECKIDENT命令(我们简单假设你在一天之内可以恢复失去的数据,那就是值为400):

DBCC CHECKIDENT ('tableName', RESEED, 29000 )
  
--Creates a gap of for the IDENTITY column to start the next value at 29000
  GO

 

  (6)使数据库联机

  一旦你已经成功做到上面的步骤,那么就更改数据库选项使它联机并且允许用户连接到数据库和运行他们的应用程序。

USE master
  
GO
  
ALTER DATABASE Northwind
  
SET MULTI_USER
  
GO

  现在数据库已经重新联机并且删除的表已经恢复。虽然现在每个人都很开心,但是作为数据库管理员,我们的工作不能就此止步。记住我们仍然需要恢复从已知良好时间点到执行DROP TABLE命令之前的缺失数据。这是我们能够恢复尽可能多的数据的唯一途径。尽管我们可以用一些第三方工具来读取事务日志和通过重放这些事务来恢复数据,但是绝大多数人没有使用这些工具的奢侈权利。所以我们下一个最好的方法是使用带有STOPAT选项的RESTORE从句。这可能有些繁琐,有时也很让人有压力,因为一个错误会让你陷入重复地执行整个过程的状态。我们所需要做的就是找出我们做备份的时间,直到事务日志备份结束。在我们的场景中,上次的备份在早上6:00,而你的已知良好时间点在早上10:42.44。因此,你可以从早上10:42.44开始执行带有STOPAT选项的RESTORE命令,并且把STOPAT时间值改成可能一秒。如果你不是很确定上次备份发生的时间,你可以一直查询MSDB数据库。

SELECT *
  
FROM msdb.dbo.backupset AS a
  
INNER JOIN msdb.dbo.backupmediafamily AS b
  
ON a.media_set_id = b.media_set_id
  
WHERE database_name = 'Northwind'
  
ORDER BY backup_finish_date

  请注意backup_finish_date和type栏,因为这些栏将会让你知道什么时候你需要考虑RESTORE命令中的STOPAT值。

  (7)用不同的名称恢复另一个损坏数据库的副本以便于研究

  用不同的名称来还愿损坏数据库的另一个副本可以让我们致力于数据的还原,而不用担心可用性,这是因为我们已经成功建立一个生产数据库。你只要确定你为恢复数据库选择了不同的名称和数据库文件位置,或者你可以结束损坏已经建立的数据库。我们将重复步骤四所做的,但是在这里使用不同的名称和数据文件位置。

RESTORE DATABASE Northwind_recover
  
FROM DISK = N'D:\DBBackup\NorthwindBackup.bak'
  
WITH MOVE N'Northwind' TO N'D:\DBBackup\NorthwindData_recover.mdf'
  MOVE N
'Northwind_Log' TO N'D:\DBBackup\NorthwindLog_recover.ldf'
  STANDBY
= N'D:\DBBackup\Northwind_UNDO.bak'
  STATS
= 10
  
GO
  
RESTORE LOG Northwind_recover
  
FROM DISK = N'D:\DBBackup\NorthwindBackupLog.trn'
  
WITH STANDBY = N'D:\DBBackup\Northwind_UNDO.bak'
  STATS
= 10, STOPAT = '2008-09-23 10:42:44.00'
  
GO

  记录你的STOPAT参数值,因为这将是你在这个过程中使用到的最关键的参数。由于我们只是重复了步骤四的过程,我们肯定知道这个时候还没有执行DROP TABLE命令。

  (8)通过提高STOPAT参数值来还原事务日志

  我们执行RESTORE LOG命令,通过一分钟 – 从10:42:44.00到 10:43:44.00来增加STOPAT参数值。

RESTORE LOG Northwind_recover
  
FROM DISK = N'D:\DBBackup\NorthwindBackupLog.trn'
  
WITH STANDBY = N'D:\DBBackup\Northwind_UNDO.bak'
  STATS
= 10, STOPAT = '2008-09-23 10:43:44.00'
  
GO

 

  这是它重复的部分。不要因为它确实繁琐而感到烦恼。你可以通过1分钟,5分钟,10分钟和记录这些时间来增加这个值。记住在执行RESTORE LOG命令之后在删除的对象上运行一个测试查询。我建议在这个活动上创建一张表,这张表看起来像这样:

TIMEOBJECT EXISTED?
  
10:43:44.00YES
  
10:48:44.00YES
  
10:58:44.00YES
  
11:03:44.00NO

  有了这个信息,你就可以很肯定地知道这张表在10:58:44.00与 11:03:44.00之间被删除。你可以重复步骤8,并且因为你已经在一个更小的时间间隔内操作,你可以在一分钟甚至一秒内增加STOPAT参数值,如果你觉得自己过度关注STOPAT参数的时间值,那么请返回带有你在步骤八中记录的列表信息的步骤七,使恢复过程更快进行。你只需要记住在上次的 RESTORE LOG语句中使用WITH RECOVERY选项,例如: 

RESTORE LOG Northwind_recover
  
FROM DISK = N'D:\DBBackup\NorthwindBackupLog.trn'
  
WITH STATS = 10, STOPAT = '2008-09-23 11:01:44.00', RECOVERY
  
GO

  一旦你设法把数据库恢复到执行DROP TABLE命令之前,你就可以在生产数据库上所做的还原和恢复所做的作一个比较。你可以用很多种方式实现这一点。由于我们已经有一个之前创建好的数据库快照,所以我们也用它来做灾难恢复。先前关于SQL Server 2005 tablediff命令行工具的方法可以让你可以了解如何使用这个工具但是只强调你的源数据库将是你恢复的那个数据库,并且目的数据库将是你的数据库快照。这是为什么你的数据库快照被证实是很重要的,尤其是如果你处理不只是一个平常的对象。如果你不习惯用命令行工具,那么可以参考一个由来自 SQLTeam.com的成员创建的GUI版本。你可能也想确定这些并且把它放在你的DBA工具栏中。

  你也可以执行一个INSERT/SELECT操作,在基于恢复数据库的一个查询的生产数据库上插入纪录。因为我们的Order Details表没有IDENTITY栏,所以可以通过在一张临时表中插入纪录和使用ROW_NUMBER()函数来自己创建这一栏。

--This inserts records in a temporary table and assigns a dummy identity value for reference
  SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS ROWID, *
  
INTO Northwind_recover.dbo.OrderDetailsRecover
  
FROM [Order Details]
  
--This inserts recovered records from the recovered database into the production database based on
  --the dummy identity valuewe have assigned for reference
  INSERT INTO Northwind.dbo.[Order Details] (OrderID,ProductId,UnitPrice,Quantity,Discount)
  
SELECT OrderID,ProductId,UnitPrice,Quantity,Discount
  
FROM Northwind_recover.dbo.OrderDetailsRecover
  
WHERE ROWID>
  (
  
SELECT COUNT(*)
  
FROM Northwind_RestorePointSnapShot.dbo.[Order Details]
  )

 

  请注意,我们使用数据库快照来识别我们所设法还原的和我们所恢复的区别。

0
相关文章