当一切正常时,没有必要特别留意什么是事务日志,它是如何工作的。你只要确保每个数据库都有正确的备份。当出现问题时,事务日志的理解对于采取修正操作是重要的,尤其在需要紧急恢复数据库到指定点时。这系列文章会告诉你每个DBA应该知道的具体细节。
在这篇文章里,我们会回顾下当运行在完整恢复模式时,为什么和如何进行日志备份,还有如何使用这些日志备份文件和完整数据库备份一起,进行数据库恢复。完整恢复模式支持数据库数据库还原到有效日志备份里的任何时间点,在尾日志已经备份的情况下,直到上一个提交事务的时间,在灾难发生前。
什么被记录?
在完整恢复模式里,所有操作被完整记录。对于INSERT,UPDATE和DELETE操作,这意味着对于修改的每一行,都有日志记录描述执行语句的事务ID,事务何时开始,何时结束,哪一页被修改,做出的数据改变等等。
当运行在完整恢复模式时,操作会被最小化记录,SELECT INTO,BULK INSERT和CREATE INDEX还是会完全记录,但有完成方法有一点区别。这些操作影响的行不是各自记录,只有数据页被记录,因为它们被填充。这会减少这类操作的日志负荷,但还是会保证存在需要同样的信息来进行回滚,重做和恢复到时间点。Kalen Delaney已经发布了对于SELECT INTO 和索引重建操作日志插入的一些研究,包括在完整和大容量日志恢复模式。当运行在大容量日志模式里时,最小化日志操作的日志区别,会在第6篇——大容量恢复模式里的日志管理里详细讨论。
为什么备份事务日志?
在完整恢复模式里,只有日志备份会引起日志截断。这样的话,自上次事务日志备份起,事务日志会保存事务运行的全部和完整记录。很多新手或业余DBA会在他们的数据库上进行完整备份,但他们不进行事务日志备份。这样的话,事务日志不会截断,不停的增长增长直到用完磁盘空间,导致SQL Server停止工作。
一旦日志备份发生,日志截断就会发生,例如自上一个备份后,且没有其他因素(例如数据备份或还原操作)延迟截断,有个检查点已发生。对于会延迟可恢复VLFs截断的完整列表,同样保持否则不需要的活动日志的大片,例如淘气的,长时间运行不提交的事务或数据库镜像或复制过程,点击查看可能引起日志截断的因素。
事务日志的复制备份
事务日志的复制备份不会截断事务日志。日志复制备份“单独”存在于普通日志备份计划里,它不会中断日志备份链。
简单来说,进行事务日志备份有2个目的:可以恢复或还原到先前一个时间点,还有控制事务日志的大小。最常见事务相关引起的问题是运行在完整恢复模式里,绝不做日志备份,或进行日志备份的频率不够控制事务日志文件的大小。
如果你不确定是否要对一个数据库进行事务日志备份,你可以简单查询下MSDB数据库里的backupset表,使用如下的查询:
1 SE msdb ; 2 SELECT backup_set_id , 3 backup_start_date , 4 backup_finish_date , 5 backup_size , 6 recovery_model , 7 [type] 8 FROM dbo.backupset 9 WHERE database_name = 'TestDB'
(代码5.1:日志备份发生了么?)
在type列里,D代表数据库备份,L代表日志备份,I代表差异备份。
注意因为backupset表里的数据不会受备份和还原行为影响,你可以从另外一个查询来验证你的发现,通过查询sys.database_recovery_status看下last_log_backup_lsn的值,或者查询sys.databases表看下log_reuse_wait_desc的值(如果备份需要的话会返回LOG_BACKUP)。
如何备份事务日志?
我们已经提过,如果不首先进行至少一次完整备份是不能进行日志备份的。事实上,你的数据库要运行在完整恢复模式,但从未备份过的话,它不是运行在完整恢复模式里的。数据库会是在自动截断模式里直到第一次完整备份完成。
数据库备份,完整,日志或者其他方面的,使用BACKUP命令进行备份。这个命令接受很多选项,它的文档在这里:https://msdn.microsoft.com/zh-cn/library/ms186865.aspx 。但是,它最基本的,进行完整备份到磁盘的命令如下:
1 BACKUP DATABASE DatabaseNameTO DISK ='FileLocationDatabaseName.bak';
如果这是第一个进行的备份,DatabaseName.bak会在指定目录里创建。如果已经存在这样的文件,默认会在那个文件增加一个序号。为了避免这个行为,保证任何已存的文件被覆盖,我们可以使用如下的INIT选项:
1 BACKUP DATABASE DatabaseNameTO DISK ='FileLocationDatabaseName.bak'WITH INIT;
通常,每个连续的备份会有一个唯一的名称;在下个部分,恢复到灾难点会有详细介绍。
在每个定期(例如每天)完整备份后,会有频繁(每小时)的日志备份,这个的基本命令非常简单:
1 BACKUP LOG DatabaseNameTO DISK ='FileLocationDatabaseName_Log.bak';
存储日志备份
很明显,数据和日志文件备份不应该和服务器存储在同个硬盘。如果那个硬盘硬件失败的话,你的所有备份会和原数据文件一起丢失,备份就没用了。文件应该备份到独立的设备,或备份到本地另一个硬盘或网络映射硬盘。
日志备份频率
在以前的文章提过,你会在每15分钟备份一次日志,甚至更高频率。这样的话,为了避免恢复大量事务日志的需要,你会选择包含有差异备份、事务日志备份穿插的完整备份计划。
实际上,备份计划经常会在理想和现实之间妥协,即在真正丢失数据的风险和公司涉及缓解磁盘花费之间。很多非常重要的业务程序使用稍微简单,但严谨的备份计划,可能涉及每晚定期的完整备份和每小时的日志备份。
日志备份的频率也会由数据库提交的日志数决定。对于非常忙碌的数据库,频繁备份来控制日志大小是很有必要的。
计算日志备份的频率是没有简单的方法。大多数DBA会采用对于日志应该备份频率的最佳估计,然后观察文件的增长情况,需要的话再调整备份计划来阻止过度增长。
日志链和如何中断它
已经提过,没有第一次至少一次的完整备份是不能进行事务日志备份的。为了恢复数据库到某个时间点,要么到特定日志备份的结尾或特定日志的某个时间点,必须要有完整不截断的日志记录链,从在完整(或差异备份)后的第一个日志备份,刚好一直到灾难时间点。这被称为日志链(log chain)。
有很多方法中断日志链,如果你有意这样做,你只能恢复数据库到日志中断事件前进行的日志备份的时间点。简单来说,如果你在意恢复你数据的能力,中断日志链不是个好方法。最常见的中断日志链的2个方法包括:
- 事务日志备份文件丢失或损坏——你只能恢复到上一次正确的日志备份。日志链会在下一个正确的完整或差异备份开始。
- 切换到简单恢复模式——如果你从完整切换到简单恢复模式,这回中断日志链,因为检查点被触发,事务日志会立即截断。当你切换回完整模式,你要进行另一个完整备份来重启日志链。事实上,在你进行完整备份前,数据库还是自动截断模式,你不能备份日志文件。
在SQL Server 2008以前,有2个命令,叫做BACKUP LOG WITH NO_LOG和BACKUP LOG WITH TRUNCATE_ONLY(功能是一样的),当被执行时,会强制日志文件截断来中断日志链。你不应该在任何版本的SQL Server里执行这些命令,但我这里提起它们是因为当处理“失控的日志文件“时,没有理解它们会影响数据库的恢复,它们会被不小心使用。我们会在第8篇——救命,我的日志满了里详细讨论。
尾日志备份
只要你有最近的一个完整备份和一个完整的日志链,你可以恢复你的数据库到任何灾难前,存在的最后日志备份的状态。但是,假设你进行的是每小时备份一次事务日志,整点备份,当灾难发生在下午1:45。你会丢失45分钟的数据;当然,如果灾难太毁灭性,备份的事务日志不能挽回,那你会丢失大量的数据。
但是,有时备份的日志还是可用的,即使数据文件已损坏,如果事务文件在独立、专门的硬盘上。如果是这样的话,你应该备份现在的事务日志,例如进行自上次日志备份后,生成日志记录的最后备份。这会捕获当前日志文件里剩余日志记录,直到灾难点。这称为尾日志备份(tail log backup),是开始恢复和还原操作前的最后应该做的操作。
尾日志备份和最小化日志操作
如果由于数据库灾难,数据文件不可用,日志尾包含最小化日志操作,那是可以进行尾日志备份,因为这需要访问在数据文件里扩展的数据修改。这在第6篇——大容量日志模式里的日志管理里会详谈。
如果你想恢复的数据库是在线的,那尾日志备份如下:
1 BACKUP LOG DatabaseNameTO DISK ='FileLocationDatabaseName_Log.bak'WITH NORECOVERY
NORECOVERY选项把数据库放入恢复状态并假设你下一个操作是还原。如果数据库是离线就不会开始,你还是应该尝试如刚介绍的尾日志备份(尽管NOCOVERY选项可以忽略,因为没有处理中的事务)。
如果你确认日式文件已损坏,微软文档建议,作为最后的方法,你用下列方法尝试进行尾日志备份:
1 BACKUP LOG DatabaseNameTO DISK ='FileLocationDatabaseName_Log.bak'WITH CONTINUE_AFTER_ERROR
如果master数据库和数据文件已损坏,但是日志还是可用的,微软建议重建master数据库然后备份最后活动日志。但这些话题已经在这个系列文章的话题之外,我给你个文档做进一步的参考:https://msdn.microsoft.com/zh-cn/library/ms190952.aspx
进行恢复和还原
进行完尾日志备份,如果可能的话,下一步是恢复最后一次完整备份(随后是差异备份,如果需要的话),然后恢复所有一系列的备份日志文件,包括尾日志备份。对这一一系列恢复操作的基本语法如下:
1 RESTORE {DATABASE | LOG} DatabaseNameFROM DISK ='FileLocationFileName.bak'WITH NORECOVERY;
当你恢复时如果你忽略WITH NORECOVERY选项,那么默认RESTORE命令会用WITH RECOVERY命令继续。换句话说,SQL Server会尝试数据和日志文件的一致,前滚完成的事务,然后回滚未完成的事务如果需要的话。通过指定WITH NORECOVERY,我们命令SQL Server我们进入一个还原步骤,在我们进行任何回滚前,很多操作需要前滚。在还原步骤里,恢复最后一次备份后,数据库可以如下进行恢复:
1 RESTORE DATABASE DatabaseName WITH RECOVERY
通常需要把数据库恢复到一个不同的位置,这样在恢复过程中你可以移动文件,如这里所介绍的:https://msdn.microsoft.com/zh-cn/library/ms190255.aspx
数据库崩溃后恢复
下面例子介绍如何对灾难数据库恢复的响应,数据文件已经不能访问。
完整恢复到失败点
假设由硬件导致数据库灾难后,当前日志还可以访问,那么理论上是可以把你的数据库恢复到灾难前的时间点,使用下列步骤:
- 备份尾日志
- 恢复最近的完整备份(加上差异备份,如何合适的话)
- 逐个恢复完整(或差异)备份后的每个事务日志备份,直到灾难前
- 恢复尾日志备份
- 恢复数据库上线
在线帮助可以找到很多从一个备份集恢复和还原演示的例子,换句话说是备份和还原在一个”设备“。实际上,这表示当备份到磁盘时,备份设备是那个磁盘上的某个.bak文件。
因此,例如下面代码展示的是使用包含一个备份文件和一个事务日志备份的备份,如何进行完整恢复。为了执行这个代码,首先你需要定位到TestDB数据库,再插入几条数据(方便起见,用脚本来做。)。你还需要在你的数据库服务器的本地C盘上创建”Backup“目录,或者修改到合适的文件路径。
1 -- Perform a full backup of the Test database 2 -- The WITH FORMAT option starts a new backup set 3 -- Be careful, as it will overwrite any existing sets 4 -- The full backup becomes the first file in the set 5 BACKUP DATABASE TestDB 6 TO DISK = 'C:BackupsTestDB.bak' 7 WITH FORMAT; 8 GO 9 10 -- Perform a transaction log backup of the Test database 11 -- This is the second file in the set 12 BACKUP Log TestDB 13 TO DISK = 'C:BackupsTestDB.bak' 14 GO 15 16 -- ....<FAILURE OCCURS HERE>.... 17 18 -- The RESTORE HEADERONLY command is optional. 19 -- It simply confirms the files that comprise 20 -- the current set 21 RESTORE HEADERONLY 22 FROM DISK = 'C:BackupsTestDB.bak' 23 GO 24 25 -- Back up the tail of the log to prepare for restore 26 -- This will become the third file of the bakup set 27 BACKUP Log TestDB 28 TO DISK = 'C:BackupsTestDB.bak' 29 WITH NORECOVERY; 30 GO 31 32 -- Restore the full backup 33 RESTORE DATABASE TestDB 34 FROM DISK = 'C:BackupsTestDB.bak' 35 WITH FILE=1, NORECOVERY; 36 37 -- Apply the transaction log backup 38 RESTORE LOG TestDB 39 FROM DISK = 'C:BackupsTestDB.bak' 40 WITH FILE=2, NORECOVERY; 41 42 -- Apply the tail log backup 43 RESTORE LOG TestDB 44 FROM DISK = 'C:BackupsTestDB.bak' 45 WITH FILE=3, NORECOVERY; 46 47 -- Recover the database 48 RESTORE DATABASE TestDB 49 WITH RECOVERY; 50 GO
(代码5.2:备份到,从备份集恢复,不推荐。)
但是,使用备份集看起来是数据库备份到磁带时留下的遗物。当备份到磁盘时,使用这个计划是个不好的想法,显然,备份文件会增长非常迅速。
实际上,常见的是每个完整备份和事务日志备份文件的每个文件名都不一样,都标记上备份发生的日期和时间。例如,大多数第三方备份工具,流行社区生成的脚本,加上SSMS里的维护计划向导/设计器,都会创建各个日期标记的文件,例如WIN8X64_AdventureWorks2008R2_FULL_20151025_120003.bak。
这样的话,更常见的备份和还原计划会使用唯一命名的备份,如下所示:
1 USE master; 2 BACKUP DATABASE TestDB 3 TO DISK ='C:BackupsTestDB.bak' 4 WITH INIT; 5 GO 6 7 -- Perform a transaction log backup of the Test database 8 BACKUP Log TestDB 9 TO DISK ='C:BackupsTestDB_log.bak' 10 WITH INIT; 11 GO 12 13 -- ....<FAILURE OCCURS HERE>.... 14 15 -- Back up the tail of the log to prepare for restore 16 BACKUP Log TestDB 17 TO DISK ='C:BackupsTestDB_taillog.bak' 18 WITH NORECOVERY, INIT; 19 GO 20 21 -- Restore the full backup 22 RESTORE DATABASE TestDB 23 FROM DISK = 'C:BackupsTestDB.bak' 24 WITH NORECOVERY; 25 26 -- Apply the transaction log backup 27 RESTORE LOG TestDB 28 FROM DISK = 'C:BackupsTestDB_log.bak' 29 WITH NORECOVERY; 30 31 -- Apply the tail log backup 32 RESTORE LOG TestDB 33 FROM DISK = 'C:BackupsTestDB_taillog.bak' 34 WITH NORECOVERY; 35 36 -- Recover the database 37 RESTORE DATABASE TestDB 38 WITH RECOVERY; 39 GO
(代码5.3:备份到,从唯一命名备份文件集还原)
恢复到上次正确日志备份的时间点
有时候很遗憾,不能进行完整恢复:例如由于灾难当前事务日志不可用。这样的话,我们会需要还原数据库导最近日志备份的末尾。我们要为这个可能做好准备,例如损坏的硬盘包含事务日志,这就决定了事务日志备份的频率。如果每15分钟备份一次,那么你就有丢失15分钟数据的风险。
假设我们已经进行了如下的一系列备份。为了演示需要,我们覆盖了先前的备份文件,实际的备份文件集明显比这个更短。
1 -- FULL BACKUP at 2AM 2 USE master ; 3 BACKUP DATABASE TestDB 4 TO DISK = 'C:BackupsTestDB.bak' 5 WITH INIT ; 6 GO 7 8 -- LOG BACKUP 1 at 2.15 AM 9 USE master ; 10 BACKUP LOG TestDB 11 TO DISK = 'C:BackupsTestDB_log.bak' 12 WITH INIT ; 13 GO 14 15 -- LOG BACKUP 2 at 2.30 AM 16 USE master ; 17 BACKUP LOG TestDB 18 TO DISK = 'C:BackupsTestDB_log2.bak' 19 WITH INIT ; 20 GO
(代码5.4:一个简短序列的日志备份)
如果灾难性故障发生在上午2:30,我们将需要恢复数据库到上午2:30的尾日志备份状态。
在这个例子的恢复步骤和我们在代码5.3里看到的非常类似,但因为不能进行尾日志备份,我们只能恢复到特定点,我们要使用代码5.5里所显示的STOPAT选项。
1 --RESTORE Full backup 2 RESTORE DATABASE TestDB 3 FROM DISK = 'C:BackupsTestDB.bak' 4 WITH NORECOVERY; 5 6 --RESTORE Log file 1 7 RESTORE LOG TestDB 8 FROM DISK = 'C:BackupsTestDB_log.bak' 9 WITH NORECOVERY, STOPAT = 'Jan 01, 2020 12:00 AM'; 10 11 --RESTORE Log file 2 12 RESTORE LOG TestDB 13 FROM DISK = 'C:BackupsTestDB_Log2.bak' 14 WITH NORECOVERY, STOPAT = 'Jan 01, 2020 12:00 AM'; 15 16 --Recover the database 17 RESTORE DATABASE TestDB 18 WITH RECOVERY; 19 GO
(代码5.5:使用STOPAT恢复到时间点)
因为我们在将来指定了STOPAT选项,这个代码会前滚所有完成的事务到第2个事务日志的结尾。
或者我们可以在特定日志文件里事务记录的时间范围里指定时间。这样的话,数据库会恢复到指定时间的最后一次提交的事务。当你知道你想恢复的时间点,却不知道那个时间包含哪些日志备份时,这个非常重要。
还有可能恢复到指定标记的事务。这是很有用的,例如,你要恢复被特定程序访问多个数据库,到逻辑一致的时间点。这个话题在这里不会详细讨论,你可以参看下微软的在线帮助(https://msdn.microsoft.com/zh-cn/library/ms187014.aspx),另外Mladen Prajdic也提供了一个很好的例子:http://weblogs.sqlteam.com/mladenp/archive/2010/10/20/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx。
“错误事务”后恢复
在任何数据库故障上下文之外,还有必要恢复数据库备份,加上事务日志,为了回到数据库的指定时间点,在错误的数据修改之前,例如删除表或清空表。
对此情况你的响应取决于问题本身。如果可能的话,你可能从数据库中断所有用户的连接(在通知它们后),评估下所发生的影响。在某些情况下,你需要估计下问题发生的时间,然后进行数据库完整恢复,恢复到日志使用的时间点。一旦恢复完成,你必须通知用户有些事务可能已经丢失,请求谅解。
当然,你不能经常在这个方式里中断正常业务操作来修正一个突发的数据丢失。因为现在的数据库还是在线,在运行,在被用户访问,你只能在STANDBY模式里尝试恢复数据库备份。这允许进一步的日志备份恢复,不像使用NORECOVERY,数据库还是可以访问的。恢复计划会如下:
- 在STANDBY模式里恢复数据库备份,在当前数据库旁(新建一个数据库)。
- 回滚记录到在错误事务发生,数据丢失前的时间点。
- 拷贝丢失的数据到当前数据库并删除恢复副本(新建的数据库)。
当然,这个过程并不简单,它会非常耗时。除非你购买了特定的日志读取工具,可以直接访问日志备份,前滚日志意味着一系列涉及到日志恢复,检查数据,进一步还原等等痛苦步骤,直到找出具体发生错误日志的位置。第3步也会非常困难,因为你在当前实时的系统里引入数据,要和当前数据库状态必须一致,因此会有一致性的问题。
我们来看下上述第1步和第2步实现的例子。
首先我们通过下列脚本重新创建TestDB数据库,在新的LogTest表里插入10条测试记录。
1 USE master 2 GO 3 4 IF EXISTS ( SELECT name 5 FROM sys.databases 6 WHERE name = 'TestDB' ) 7 DROP DATABASE TestDB ; 8 9 CREATE DATABASE TestDB ON 10 ( 11 NAME = TestDB_dat, 12 FILENAME = 'C:Program FilesMicrosoft SQL ServerMSSQL10_50.MSSQLSERVERMSSQLDATATestDB.mdf' 13 ) LOG ON 14 ( 15 NAME = TestDB_log, 16 FILENAME = 'C:Program FilesMicrosoft SQL ServerMSSQL10_50.MSSQLSERVERMSSQLDATATestDB.ldf' 17 ) ; 18 19 USE TestDB 20 GO 21 IF OBJECT_ID('dbo.LogTest', 'U') IS NOT NULL 22 DROP TABLE dbo.LogTest ; 23 SELECT TOP 10 24 SomeID = IDENTITY( INT,1,1 ), 25 SomeInt = ABS(CHECKSUM(NEWID())) % 50000 + 1 , 26 SomeLetters2 = CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65) 27 + CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65) 28 INTO dbo.LogTest 29 FROM sys.all_columns ac1 30 CROSS JOIN sys.all_columns ac2 ; 31 GO 32 USE master 33 GO
在代码5.6里,我们直接进行一个完整数据库备份(覆盖先前的任何备份文件)。你需要创建“Backups”目录,如果你已经做了,或者调整到合适目录。
1 -- full backup of the database 2 BACKUP DATABASE TestDB 3 TO DISK ='C:BackupsTestDB.bak' 4 WITH INIT; 5 GO
(代码5.6:TestDb的完整备份)
然后我们插入一条新纪录到LogTest表。
1 USE TestDB 2 GO 3 INSERT INTO [TestDB].[dbo].[LogTest] 4 ([SomeInt] 5 ,[SomeLetters2]) 6 VALUES 7 (66666, 8 'ST') 9 10 SELECT * FROM dbo.LogTest
(代码5.7:插入TestDB第11行)
现在我们当前TestDB数据库的LogTest表有11条记录,备份版本里有10条记录。现在我们在日志备份里捕获额外的修改,如代码5.8所示:
1 USE master 2 GO 3 BACKUP Log TestDB 4 TO DISK ='C:BackupsTestDB_log.bak' 5 WITH INIT; 6 GO
(代码5.8:TestDB的日志备份)
现在,我们来模拟一个错误的“坏事务”,直接删除LogTest表,之后我们进行最后日志备份。
1 USE TestDB 2 GO 3 DROP TABLE dbo.LogTest ; 4 5 USE master 6 GO 7 BACKUP Log TestDB 8 TO DISK ='C:BackupsTestDB_log2.bak' 9 WITH INIT; 10 GO
(代码5.9:灾难发生!)
为了尝试找回丢失的数据,不中断正常业务操作,我们来还原一个在STANDBY模式里TestDB数据库的副本。Standby模式数据库的数据和日志叫做ANewTestDB,移动到”Standby“目录(你要事先创建这个目录)。
1 -- restore a copy of the TestDB database, called 2 -- ANewTestDB, in STANDBY mode 3 USE master ; 4 GO 5 RESTORE DATABASE ANewTestDB 6 FROM DISK ='C:BackupsTestDB.bak' 7 WITH STANDBY='C:BackupsANEWTestDB.bak', 8 MOVE 'TestDB_dat' TO 'C:StandbyANewTestDB.mdf', 9 MOVE 'TestDB_log' TO 'C:StandbyANewTestDB.ldf' 10 GO
(代码5.10:在STANDBY模式里恢复TestDB副本)
现在我们有一个名为ANewTestDB的数据库,它在”备用/只读“模式里,如下所示:
(图5.1:待命数据库)
对ANewTestDB数据库的Lost表查询会返回10条记录。但是我们想把表恢复到在删除之前的状态。因此,下一步进行对待命数据库进行日志备份还原。
1 USE master 2 GO 3 RESTORE LOG ANewTestDB 4 FROM DISK = 'C:BackupsTestDB_log.bak' 5 WITH STANDBY='C:BackupsANewTestDB_log.bak'
(代码5.11:在待命模式里的ANewTestDB数据库里,恢复日志备份)
这个时候,ANewTestDB数据库已经恢复11条记录,我们可以拷贝这些记录到TestDB数据库。如果我们进一步,还原第2个日志备份,我们会发现我们走过头了,LogTest表同样在待命数据库里丢失了。
其他进行待命还原是考虑使用例如Red Gate的SQL Virtual Restore的第三方工具,它提供多个数据库备份文件直接还原,数据库正常运行,不需要物理还原的方法。
不管DBA是否喜欢,开发者经常访问生产数据库进行即席数据读取和修改。保持这些操作正常进行是DBA和开发者的连带责任,因此不要引起刚才介绍这类操作的问题。我们会在第6篇——处理大容量操作里继续讨论这个话题。
当然,修复行动的本身需要取决于错误事务的本身。如果表被”不小心删除“,那你可以进行RESTORE
WITH
STANDBY
方法。其他时间,你可以直接创建脚本来反向这些流氓修改。
如果损坏只影响到单列或少量行,那么可以使用SQL Data Compare这样的工具,可以直接和备份文件比较,可以进行级别的还原。
另外,如果你使用SQL Server 2005(或更高)的企业版本,我们有最近数据库快照功能,你可以执行快照查询来取回数据库执行快照时的数据,然后写UPDATE或INSERT命令把快照里是数据写入当前运行的数据库。
最后,作为最后一招,专门的日志读取工作会帮你逆向事务的影响,尽管我不知道在SQL Server 2005和后续版本里的运行的任何可靠性。
小结
在这篇文章里,我们讨论了在完整恢复模式里,备份的基本和对数据库日志文件恢复,这些都是生产数据库的常规操作。
对大多数DBA,进行时间点恢复是很少的,但它是这些工作之一,如果需要的话,做且做好它是绝对必要的;DBA的名声取决于它。
在灾难情况里,硬盘故障等等,会涉及时间点的恢复,如果你幸运的话,可以做尾日志的备份,那你可以恢复到灾难前的时间点。如果事务日志不可用,或者你为了恢复到逆向”错误事务“发生前的时间点,那么情况变得棘手,希望这篇文章里这一步谈到的一些技术可以帮到你。