事务日志管理的阶梯

SQL Server中事务日志管理的阶梯,级别6:在BULK_LOGGED恢复模型中管理日志

,

这个标题有点用词不当,因为我们通常不会通过在散装_记录恢复模型。然而,DBA可以考虑将数据库切换到批量日志记录短期内的恢复模式,例如散装操作。当数据库在散装_记录对这些操作和一些其他操作(如索引重建)进行建模,可以是最低限度地 记录因此,将在日志中使用更少的空间。当为非常大的表重建聚集索引时,或者当大容量加载数百万行数据时,在散装_记录恢复模型,与FULL(满)恢复模型,可以是非常实质性的。

然而,我们应该使用散装_记录只有在充分了解其影响的情况下才能恢复数据库还原和恢复例如,在包含与日志记录最少的操作相关的日志记录的日志备份中,不可能恢复到特定的时间点。此外,还有一种特殊情况,如果数据库在中操作时记录了最小日志记录操作,则尾日志备份将失败批量日志记录恢复模型,存在于事务日志的活动部分,并且数据文件由于灾难(例如磁盘故障)而变得不可用。

如果在灾难发生的时间方面运气不佳,那么这些限制中的任何一个都可能导致数据丢失。检查有关数据库的服务级别协议(SLA),以了解可接受的数据丢失级别;如果它表示零容忍,那么使用散装_记录模型,即使是短期的,也是可以接受的。相反,当然,如果这样的数据库需要定期进行索引重建或批量加载,那么数据库所有者必须了解在FULL(满)恢复模型。

综上所述,对于许多数据库来说,能够切换到散装_记录恢复使SQL Server将某些操作的日志降到最低,是对抗日志过度增长的一个非常有用的武器。在大多数情况下,SLA将允许有足够的余地使其使用可以接受,并且通过仔细的规划和程序,风险将降到最低。

这一级别将包括:

  • 我们所说的“最小日志记录”是什么意思
  • 从日志空间使用的角度来看,最小日志记录的优点
  • 最小日志记录对崩溃恢复、点时间恢复和尾日志备份的影响
  • 使用的最佳实践散装_记录恢复。

最少记录的操作

当数据库在FULL(满)恢复模型中,所有操作都被完全记录。这意味着每个日志记录都存储了足够的信息来回滚(undo)或前滚(redo)它描述的操作。给定日志文件中的所有日志记录都已完全记录,我们可以完整地描述在该时间段内对数据库所做的所有更改。这意味着,在还原操作期间,SQL Server可以前滚每个日志记录,然后将数据库恢复到该日志文件中任何时间点存在的确切状态。

当数据库在中操作时批量日志记录(或简单)恢复模型中,SQL Server可以最低限度地记录某些操作。虽然一些最小日志记录的操作很明显(散装插入件、bcp或索引重建),其他则不是。例如,插入…选择在SQL Server 2008和更高版本中,在某些情况下可以最少记录日志。(请参见http://msdn.microsoft.com/en-us/library/ms191244%28v=sql.100%29.aspx详细信息。)

您可以在此处找到SQL Server可以最少记录的操作的完整列表:http://msdn.microsoft.com/en-us/library/ms191244.aspx。一些比较常见的如下所示:

  • 批量装载操作–例如通过SSIS、bcp或散装插入件
  • 选择INTO操作
  • 创建和重建索引。

值得注意的是,“可以”最小日志与“将要”最小日志不同。根据适当的索引和优化器选择的计划,SQL Server可能仍然会完全记录批量加载操作,理论上,它可以将这些操作记录得最少。由于(主要)可恢复性要求,SQL Server只记录正在分配的大量数据负载新扩展数据块例如,如果我们对已经包含一些数据的聚集索引执行批量加载,则加载将包括添加页面、拆分页面和分配新页面,因此SQL Server无法最低限度地进行日志记录。类似地,SQLServer可以将最小的插入记录到表中,而将完全的插入记录在非聚集索引中。请参阅白皮书,这个 数据加载性能指南, (http://msdn.microsoft.com/en-us/library/dd425070.aspx)进行更全面的讨论。

Books Online将最小日志记录操作描述为“只记录恢复事务所需的信息,而不支持点式恢复”。类似地,Kalen Delaney在她的书中,SQL Server 2008内部(第4章,第199页)将最小日志记录操作定义为“只记录足够的信息以回滚事务,而不支持点时间恢复的操作。”

为了了解“最小日志记录”操作所记录内容之间的差异,这取决于数据库是否使用FULL(满)散装_记录恢复,让我们试试看!

数据和备份文件位置

此级别中的所有示例都假设数据和日志文件位于“D:\SQLData”和中的所有备份“D:\SQLBackups”分别是。在运行示例时,只需根据您的系统修改这些位置即可(请注意,在实际系统中,我们不会将所有内容都存储在同一个驱动器上!)。

我们将使用选择…进入语句,该语句可以在SQL Server 2008中最低限度地记录,以将200行(每行2000字节)插入名为SomeTable公司。由于SQL Server中的页面大小为8 KB,因此每页应该有四行,总共有50个数据页(加上一些分配页)。清单6.1创建了一个测试数据库,完全恢复,确保其在中运行FULL(满)恢复模型,然后运行选择…进入声明。

USE主控形状GO(开始)如果DB_ID(“FullRecovery”)不是NULL,则删除数据库FullRecover;GO--清除备份历史EXEC msdb.dbo.sp_delete_database_backuphistory@database_name=N'FullRecovery'GO CREATE database FullRecovery ON(name=FullRecovery_dat,FILENAME='D:\SQLData\FullRecovery.mdf')LOG ON(name=FullRecovery.LOG,FILENAME='D:\SQLData\FullRecovery.ldf');ALTER DATABASE FullRecovery SET RECOVERY FULL GO BACKUP DATABASE FullRecover TO DISK='D:\SQLBackups\FullRecoverion.bak'WITH INIT GO USE FullRecovery GO IF OBJECT_ID('dbo.SomeTable','U')IS NOT NULL DROP TABLE dbo。SomeTable GO SELECT TOP(200)REPLICATE('a',2000)AS SomeCol TO SomeTable-从sys.columns AS c;

清单6.1:运行选择…进入对的操作FULL(满)恢复模型数据库。

现在,我们想查看日志内部,并了解SQL Server在日志中记录了什么,因为我们的日志已完全记录选择…进入声明。有一些第三方日志读取器用于此目的,但其中很少有提供SQL Server 2005以外的支持。然而,我们可以使用两个没有文档记录且不受支持的函数来查询日志文件(fn_dblog)和日志备份(fn_dump_dlog)的内容,如清单6.2所示。

SELECT操作,上下文,分配单元名称,--说明,[日志记录长度],[日志记录]来自fn_dblog(NULL,NULL)

清单6.2:使用fn_博客.

图6.1显示了由一组八页组成的输出的一小部分(其中分配单元为数据库管理员。有点稳定). 请注意,每种情况下的上下文是LCX_加热炉,所以这些是数据页。我们还看到一些分配页面,在本例中是差异变化图,跟踪自上次数据库备份以来发生更改的扩展数据块(以便于差异备份),以及一些页面可用空间(PFS)页面,跟踪页面分配和页面上的可用可用空间。

图6.1:fn_dblog输出选择…进入FULL(满)恢复模型数据库。

描述对所做更改的日志记录SomeTable公司都是类型LOP_FORMAT_PAGE(LOP_FORMAT_PAGE); 它们总是以8个一组的形式出现,每个都有8276字节长。它们以8个一组出现的事实表明,SQL Server每次处理一个数据块的插入,并为每个页面写入一条日志记录。每个都是8276个字节,这表明每个都包含整个页面的图像以及日志头。换句话说,对于将…插入命令,以及SQL Server将最少登录的其他命令散装_记录恢复,SQL Server在运行时不会记录每一行FULL(满)恢复;相反,它只是在填充时记录每个页面图像。

日志记录列显示包含十六进制值的许多字节0x61个,如图6.2所示。这转换为十进制97,这是“a”的ASCII值,因此这些是日志文件中的实际数据行。

图6.2:详细查看日志记录。

所以在FULL(满)SQL Server只需读取日志文件就可以知道恢复模型,哪些数据块发生了更改,以及这对页面内容的确切影响。现在,让我们将其与执行相同操作所产生的日志记录进行比较选择…进入在中对数据库进行操作散装_记录恢复。

USE主控形状GO(开始)如果DB_ID('BulkLoggedRecovery')不为空DROP数据库BulkLoggedRecovery;GO(开始)EXEC msdb.dbo.sp_delete_database_backupchistory@database_name=N'大容量日志恢复'GO(开始)打开CREATE DATABASE BulkLoggedRecovery(名称=BulkLoggedRecovery_dat,文件名='D:\SQLData\BulkLoggedRecovery.mdf')登录(NAME=BulkLoggedRecovery日志,文件名=“D:\SQLData\BulkLoggedRecovery.ldf”);GO(开始)ALTER DATABASE BulkLoggedRecovery集合恢复BULK_LOGGEDGO(开始)将数据库BulkLoggedRecovery备份到磁盘=“D:\SQLBackups\BulkLoggedRecovery.bak”带初始GO(开始)使用BulkLoggedRecoveryGO(开始)如果OBJECT_ID('dbo.SomeTable','U')不是NULL,请删除表dbo。SomeTable GO SELECT TOP(200)REPLICATE('a',2000)AS SomeCol TO SomeTable-从sys.columns AS c;

清单6.3:运行选择…进入对的操作批量日志记录恢复模型数据库。

重新运行fn_博客函数中的批量记录恢复数据库,这次我们得到的是一组非常不同的日志记录。没有LOP_FORMAT_PAGE(LOP_FORMAT_PAGE)日志记录。

图6.3:fn_博客之后的输出选择…进入散装_记录数据库。

这一次,日志记录对SomeTable公司显示在全局分配图(GAM)和索引分配图(IAM)的上下文中,跟踪扩展数据块分配,以及一些PFS页面。换句话说,SQL Server正在记录数据块分配(以及元数据的任何更改,即系统表,我们在图6.3中没有显示),但数据页本身并不存在。日志中没有引用分配页面上的数据。我们在这里看不到出现在的日志记录中的0x61模式完全恢复数据库,并且大多数日志记录的大小约为100字节。

因此,现在我们更清楚地了解了SQL Server将操作日志最小化的确切含义:它是SQL Server记录相关扩展数据块的分配,而不是这些扩展数据块(即数据页)的实际内容。

其影响是双重的。首先,这意味着SQL Server向事务日志写入的信息要少得多,因此日志文件的增长速度将大大低于FULL(满)恢复模型。这也意味着批量装载操作可以更快(但请参阅后面关于此主题的讨论,在最小日志记录和散装_记录恢复).

然而,第二,这意味着SQL Server只记录足够的信息来撤消(回滚)日志记录最少的操作所属的事务,而不是重做(前滚)。回滚包含选择…进入操作时,SQL Server只需取消分配受影响的页面。由于页面分配被记录下来,如图6.3所示,这是可能的。向前滚动事务是另一回事。日志记录可用于重新分配页面,但当操作日志记录最少时,SQL Server无法使用这些日志记录重新创建页面的内容。

最少记录与“仅数据块取消分配”

对于DROP表格截断表操作,对于批量操作,SQL Server只记录数据块取消分配。然而,前者不是真正的最小日志操作,因为它们的行为在全部的恢复模型。真正的最小日志操作的行为在FULL(满)从中恢复散装_记录(或简单)根据SQL Server日志恢复。此外,对于真正的最小日志记录操作,当进行日志备份时,SQL Server会将受最小日志记录的操作影响的所有数据页捕获到备份文件中(稍后我们将对此进行更详细的讨论),以便在还原操作中使用。这种情况不会发生在DROP表格截断表命令。

最小日志记录和BULK_LOGGED恢复的优点

在我们讨论使用的潜在问题之前散装_记录恢复,让我们讨论一下DBA的主要优势。

操作可以最低限度地记录在简单散装_记录恢复模型。然而,如果我们从FULL(满)简单恢复模型,我们触发检查点,这将截断日志,我们立即断开LSN链。在数据库切换回之前,无法进行进一步的日志备份FULL(满)(或散装_记录)恢复,并且使用完整数据库备份重新启动日志链,或者我们使用差异数据库备份“弥合LSN差距”。

正在切换到散装_记录FULL(满)然而,恢复不会中断日志链。将数据库从FULL(满)恢复到散装_记录恢复;它立即生效。类似地,在切换回FULL(满)恢复。但是,最好在切换到之前立即进行日志备份散装_记录以及在切换回后立即(请参见最佳实践用于BULK_LOGGED第节,供进一步讨论)。

尽管在切换到散装_记录模型,我们稍后将详细讨论,就数据丢失风险而言,它是一个更安全的选项,因为日志链保持不变。一旦数据库在散装_记录模型中,真正的优点是减少了可以最少记录的操作所使用的日志空间,并且这些操作的性能可能会得到改进。

让我们看一个索引重建的示例,这是一个可以最少记录日志的操作。FULL(满)恢复模型中,索引重建操作需要大于或等于表大小的日志空间。对于大型表,这可能会导致大量日志增长,这是许多陷入困境的用户的论坛条目的根本原因,大致是“我重建了索引,我的日志增长巨大/磁盘空间不足!”

散装_记录恢复时,只记录新索引的页面分配,因此对事务日志的影响可能会大大小于FULL(满)恢复。类似的参数适用于通过bcp或散装插入件,或通过将数据复制到新表中选择…进入插入…选择.

为了了解这有多大的不同,让我们看一个例子。首先,我们将创建一个具有聚集索引的表,并用数据加载它(Filler列为每行添加1500字节,并确保我们得到一个具有多个页面的表)。

使用完全恢复GO(开始)如果OBJECT_ID('dbo.PrimaryTable_Large','U')不为空删除表dbo。主表_大GO(开始)创建表格主表TABLE_Large(ID INT标识主钥匙,某些列CHAR(4)为空,填充字符(1500)默认值“”);GO(开始)插入到PrimaryTable_Large(某些列)选择前100000名“abcd”FROM msdb.sys.columns来自msdb.sys列交叉联接msdb.sys.columns bGO(开始)选择*自sys.dm_db_index_physical_stats(db_ID(N’FullRecovery’),对象ID(N'主表_大'),NULL、NULL、'DETAILED');

清单6.4:创建和加载PrimaryTable_Large。

现在让我们重建聚集索引(根据系统.dm_db索引物理状态)在我们的FULL(满)恢复模型数据库,并查看索引重建需要多少日志空间,与一起使用系统dm_tran_database_transactionsDMV公司。

--截断日志USE主控形状GO(开始)备份日志完全恢复到磁盘='D:\SQLBackups\FullRecovery_log.trn'带初始GO(开始)--重建索引并查询事务中的日志空间使用情况使用完全恢复GO(开始)开始交易将索引全部更改为dbo。主表_大型重建--只有聚集索引选择d.name,--会话id,d.恢复模型,--数据库事务开始时间,数据库事务日志记录计数,使用的数据库事务日志,DATEDIFF(ss,数据库事务开始时间,GETDATE())AS秒重建来自sys.dm_tran_database_transactions AS dt内部联接系统.dm_tran_session_transactions AS stON dt.transaction_id=st.transation_id内部联接sys.databases AS d ON dt.database_id=d.database_ idWHERE d.name=“完全恢复”提交交易

清单6.5:重建聚集索引时的日志空间使用情况。

当我在运行中的数据库上运行此代码时FULL(满)回收率,DMV的输出如图6.4所示。

图6.4:中的索引重建时间和日志空间使用情况FULL(满)恢复。

重建索引大约需要5秒钟,重建20131个日志记录需要约166MB的日志空间;这是在回滚时忽略日志保留,因此所需的总日志空间更大。

如果我们在批量记录恢复数据库,输出如图6.5所示。

图6.5:中的索引重建时间和日志空间使用散装_记录恢复。

重建速度似乎快了一点,只需4秒;然而,由于本例中的索引非常小,并且数据和日志文件都在一个驱动器上,因此从时间差中可以得出的结论不多。这里的重点是所使用的日志空间的差异。散装_记录恢复时,该索引重建只使用了大约0.6 MB的日志空间,而在FULL(满)恢复。考虑到这是一个非常小的表,只有160MB的大小,这是一项很大的节省。

万一有人想知道简单恢复,请参见图6.6(在简单的恢复数据库,以及散装_记录,包含在该级别的代码下载中)。

图6.6:中的索引重建时间和日志空间使用简单恢复。

正如预期的那样,行为与散装_记录恢复,因为最少登录的操作散装_记录恢复的登录次数也最少简单恢复。

这是在中运行数据库的主要原因散装_记录恢复;它提供了以下两种数据库恢复选项FULL(满)恢复(大多数情况下,请参阅后面的部分),但它以与以下相同的方式减少了某些操作使用的日志空间量简单的恢复。还要注意,如果数据库是日志传送主数据库,则不能将数据库切换为简单索引恢复将重建,而无需在以后重新进行日志传送,但我们可以将其切换为散装_记录用于重建索引。

最后,请注意,数据库镜像需要FULL(满)仅恢复,因此作为数据库镜像主体的数据库不能使用散装_记录恢复。

最小记录操作的含义

前面,我们讨论了当数据库在散装_记录恢复时,日志只包含数据块分配(加上元数据),而不包含最低日志记录操作的实际结果(例如,不包含插入的实际数据)。这意味着日志本身只保存了足够的信息来回滚事务,而不是重做事务。为了执行后者,SQL Server需要读取描述操作的日志记录受操作影响的实际数据页。

每当SQL Server需要重做事务时,即在事故恢复、和在数据库期间恢复操作。它还对日志备份操作在SQL Server必须将哪些内容复制到备份文件中,以及在哪些情况下这可能或不可能。

碰撞恢复

崩溃恢复(也称为重新启动恢复)是SQL Server在使数据库联机时执行的一个过程。因此,例如,如果数据库没有完全关闭,那么在重新启动SQL Server时,会检查数据库的事务日志。它撤消关闭时未提交的任何事务,并重做已提交但其更改未持久化到磁盘的任何事务。

这是可能的,因为如级别1中所述预写日志记录该机制确保在事务提交或数据修改写入磁盘之前(以先发生的为准),将与数据修改关联的日志记录写入磁盘。SQL Server可以在事务提交之前或之后的任何时候,通过检查点或Lazy Writer将更改写入数据文件。因此,对于正常操作(即完全记录的操作),SQL Server在事务日志中有足够的信息来指示操作是否需要撤消或重做,并且有足够的消息来前滚或回滚。

然而,对于日志记录最少的操作,前滚是不可能的,因为日志中没有足够的信息。因此,在处理中的最小日志记录操作时简单散装_记录恢复模型,另一个过程,渴望写入,保证在事务完成之前,执行大容量操作的线程将由最少日志操作修改的任何扩展数据块硬化到磁盘。这与正常操作不同,在正常操作中,只有日志记录必须在事务完成之前硬化,并且数据页稍后由系统进程(Lazy Writer或检查点)写入。

这意味着崩溃恢复永远不必重做日志记录最少的操作,因为SQL Server保证在事务提交时修改的数据页将在磁盘上,因此日志记录最少对崩溃恢复过程没有影响。

此要求的一个副作用是,SQL Server在事务提交之前将日志记录和修改过的数据页都写入磁盘,这实际上可能导致日志记录最少的操作更慢的如果数据文件无法处理大量写入,则与常规事务相比。日志记录最少的操作通常比正常操作快,但无法保证。唯一的保证是他们写较少的事务日志中的信息。

数据库恢复

在还原完整备份、差异备份或日志备份时,SQL Server还需要执行重做操作。正如我们所讨论的,对于日志记录最少的操作,受影响的页面在事务完成时位于磁盘上,因此SQL Server只需将这些页面复制到任何完整或差异备份文件中,而从这些备份中进行的恢复不受影响。

然而,从日志备份恢复更有趣。如果日志备份仅包含与数据块分配相关的日志记录,那么在恢复日志备份时,将无法重新创建受最小日志记录操作影响的数据块的内容。这是因为,正如我们前面看到的,日志不包含插入的数据,只包含数据块分配和元数据。

为了在存在日志记录最少的操作时启用日志恢复,日志备份中不仅包括日志记录,还包括受日志记录最少操作影响的任何范围(八页集)的映像。这个没有't吨指的是最小日志记录操作后的图像,但指的是日志备份时的页面。SQL Server维护一个位图分配页,称为ML地图批量更改图,每个范围都有一个位。受最小日志记录操作影响的任何扩展数据块的位都设置为1。日志备份操作会读取此页面,因此确切知道要在备份中包含哪些扩展数据块。然后,该日志备份将清除ML映射。

例如,假设我们有一个如图6.7所示的时间表,其中日志备份发生在10:00,然后是(1)一个最小日志操作(假设散装插入件)受影响的页面1308–1315,在(2)更新受影响的页1310和1311,以及在(3)发生另一个日志备份。

图6.7:数据库操作和日志备份的时间线示例。

10:30的日志备份将备份10:00–10:30期间的日志记录。由于在该日志间隔内有一个日志记录最少的操作,因此它会将受日志记录最少操作影响的扩展数据块复制到日志备份中。它按照日志备份时出现的方式复制它们,因此它们将反映散装插入件更新,以及可能在更新和日志备份。

这会影响我们恢复日志的方式。它还影响日志备份的大小,在某些情况下,可能会影响尾部日志备份,但我们将在下一节中对此进行更详细的介绍。

让我们看一个示例,看看日志记录最少的操作如何影响点时间恢复。图6.8描述了两个数据库的相同备份时间表。绿色条表示完整的数据库备份,黄色条表示一系列日志备份。这两个数据库之间的唯一区别是,第一个数据库在FULL(满)恢复模型和第二个散装货物已记录.

图6.8:数据库备份时间表。

第五次日志备份的时间跨度是10:00到10:30。10:10,a散装插入件命令(1)加载了一组数据。此批量数据加载顺利完成,但在10:20的一次无关事件中,一个用户运行了一次“恶意”数据修改(2),关键数据丢失。项目经理通知DBA团队,并要求他们将数据库恢复到10:20导致数据丢失的事务开始之前的某个时间点。

FULL(满)恢复模型数据库,这不是问题。批量数据加载已被完全记录,我们可以将数据库恢复到该日志文件中的任何时间点。我们只需恢复最后一次完整数据库备份,而不进行恢复,并使用恢复日志带有的命令STOPAT公司参数,以在10:20之前的某个时间停止恢复操作。

散装_记录数据库,我们有一个问题。我们可以恢复到前四个日志备份中的任意时间点,但不能恢复到第五个日志备份(其中包含日志记录最少的操作)中的任何时间点。请记住,对于此日志备份,我们只有受最低记录操作影响的扩展数据块,因为它们在日志备份时就存在。第五次日志备份的恢复是“全有或全无”:要么不应用此日志文件中的任何操作,在第四个文件末尾停止恢复,要么应用所有操作,恢复到文件末尾,或者继续恢复到第六次日志备份中的任何时间点。

如果我们试图恢复第五次日志备份停止10:15(在最低日志记录操作和恶意修改之间的一段时间),SQL不会遍历日志备份的其余部分,以确定需要在受最低日志记录的操作影响的页面上撤消哪些操作。它的反应更简单:

消息4341,级别16,状态1,行2

此日志备份包含大容量记录的更改。它不能用于在任意时间点停止。

不幸的是,如果我们应用第五次日志文件备份的全部内容,这将无法实现恢复的目的,因为错误的进程将其更改提交到该日志备份文件中的某个位置,所以我们只需删除我们试图取回的数据!我们别无选择,只能恢复到第四个日志的末尾,恢复数据库,并报告在此之后所做的任何数据更改的丢失。

如果日志间隔内记录的操作最少,则无法将数据库恢复到点时间,这是在选择在中运行数据库时必须考虑的问题散装_记录短期或长期恢复。很容易确定特定日志备份是否包含任何日志记录最少的操作。A类仅恢复标题返回有关相关备份的一组详细信息,包括一列HasBulk记录数据此外msdb备份表中有一列_散装_记录_数据。如果列值为1,则日志备份包含日志记录最少的操作,并且只能完全恢复或根本不能恢复。也就是说,在计划或执行恢复时发现这一点可能会是一个令人不快的惊喜。

日志备份大小

需要将受最小日志记录操作影响的页面复制到日志备份中会影响日志备份的大小。从本质上讲,这意味着虽然在散装_记录恢复数据库,与FULL(满)恢复数据库时,日志备份的大小不会小于,有时可能会大于FULL(满)恢复数据库。

查看最低日志记录操作的可能影响,以及散装_记录关于日志备份大小的恢复模型,我们将看一个简单的示例。首先,重新运行清单6.3中删除并重新创建BulkLoggedRecovery数据库的部分,将恢复模型设置为散装_记录然后进行完整的数据库备份。接下来,运行清单6.6在SomeTable公司.

使用BulkLoggedRecoveryGO(开始)如果OBJECT_ID('dbo.SomeTable','U')不为空删除表dbo。SomeTable;选择前500000名SomeCol=复制('a',2000)INTO数据库。SomeTable公司来自sys.all_columns ac1交叉联接sys.all_columns ac2;GO(开始)

清单6.6:将500K行插入SomeTable公司在中批量记录恢复数据库。

接下来,我们检查当前的日志空间使用情况,然后备份日志。

DBCC SQLPERF(LOGSPACE);--24 MB--截断日志USE主控形状GO(开始)备份日志大容量日志恢复到磁盘='D:\SQLBackups\BulkLoggedRecovery_log.trn'带初始GO(开始)

清单6.7:备份的日志批量记录恢复.

考虑到日志大小只有约24MB,您可能会惊讶地看到日志备份的大小,在我的测试中约为1GB!对于中的数据库FULL(满)恢复时,您会发现日志大小和日志备份大小都约为1GB。

尾日志备份

让我们想象一下,硬件故障导致了一些数据损坏,但数据库仍然在线,我们希望通过该数据库进行恢复。使用执行尾日志备份备份日志…使用NORECOVERY,将捕获日志文件的其余内容,并将数据库置于还原状态,这样,针对该数据库的任何其他事务都不会成功,我们可以开始还原操作。这种类型的尾日志备份和常规日志备份一样,要求数据库处于联机状态(以便SQL Server可以将有关日志备份的信息标记到数据库标头中)。

然而,假设数据文件损坏严重到数据库不可用,并且尝试使其恢复联机失败。如果数据库位于FULL(满)恢复模型,使用常规日志备份,只要日志文件仍然可用,我们就可以进行尾部日志备份,但使用不运行(_T)选项,即。备份日志…没有运行。此操作备份日志文件而不截断它,并且不要求数据库联机。

使用现有备份(完整备份,可能是差异备份,然后是日志备份)和尾部日志备份,我们可以将数据库恢复到它失败的确切位置。我们可以这样做,因为日志包含足够的信息来重新创建所有提交的事务。

但是,如果数据库位于散装_记录恢复,并且事务日志的活动部分中记录的操作最少,那么日志中就没有足够的信息来重新创建所有已提交的事务,并且在进行尾日志备份时,实际的数据页需要可用。如果数据文件不可用,则日志备份无法复制恢复一致数据库所需的数据页。让我们看看这个实际操作,使用批量记录恢复数据库。

备份数据库BulkLoggedRecovery到磁盘='D:\SQLBackups\BulkLoggedRecovery2.bak'带初始GO(开始)使用BulkLoggedRecoveryGO(开始)如果OBJECT_ID('dbo.SomeTable','U')不为空删除表格dbo。SomeTable;选择前200名SomeCol=复制('a',2000)INTO数据库。SomeTable公司来自sys.all_columns ac1GO(开始)无需停机

清单6.8:创建批量记录恢复数据库,执行选择INTO,然后关闭。

关闭SQL Server服务后,转到数据文件夹并删除中密度纤维板的文件批量记录恢复数据库,然后重新启动SQL Server。这并不是一个完整的驱动器故障模拟,但它已经足够接近本演示的目的。

当SQL Server重新启动时,数据库不可用,这并不奇怪,因为它的主数据文件丢失了。州是恢复_挂起,这意味着SQL无法打开数据库以对其运行故障恢复。

USE主控形状GO(开始)选择名称,状态_desc来自系统数据库WHERE name=“BulkLoggedRecovery”名称state_desc---------------------------------------批量记录恢复_结束

清单6.9:批量记录恢复数据库位于恢复_挂起状态。

在清单6.10中,我们尝试进行尾日志备份(注意不运行(_T)暗示COPY_ONLY(仅限副本)继续_后_错误):

备份日志大容量日志恢复TO DISK='D:\SQLBackups\BulkLoggedRecovery_tail.trn'没有运行已为文件1上的数据库“BulkLoggedRecovery”和文件“BulkNoggedRecovery_log”处理了7页。BACKUP WITH CONTINUE_AFTER_ERROR成功生成了损坏数据库的备份。有关遇到的错误的信息,请参阅SQL Server错误日志。备份日志在0.007秒(7.463 MB/秒)内成功处理了7页。

清单6.10:使用备份日志…没有运行.

它说它成功了(尽管有警告,但错误日志中没有错误)。现在,让我们尝试恢复这个数据库,如清单6.11所示。

恢复数据库批量日志恢复从磁盘='D:\SQLBackups\BulkLoggedRecovery2.bak'带NORECOVERY恢复日志批量日志恢复从磁盘='D:\SQLBackups\BulkLoggedRecovery_tail.trn'带恢复功能已为文件1上的数据库“BulkLoggedRecovery”、文件“BulkNoggedRecover”处理184页。已为文件1上的数据库“BulkLoggedRecovery”和文件“BulkNoggedRecovery_log”处理了3个页面。RESTORE DATABASE在0.043秒内(33.895 MB/秒)成功处理了187页。消息3182,16级,州2,第5行无法还原备份集,因为备份时数据库已损坏。打捞尝试可能会利用WITH CONTINUE_AFTER_ERROR进行攻击。消息3013,16级,州1,第5行RESTORE LOG异常终止。

清单6.11:尝试恢复批量记录恢复.

恢复数据库批量日志恢复FROM DISK='D:\SQLBackups\BulkLoggedRecovery 2.bak'带NORECOVERY恢复日志批量日志恢复从磁盘='D:\SQLBackups\BulkLoggedRecovery_tail.trn'带恢复,CONTINUE_AFTER_ERROR已为文件1上的数据库“BulkLoggedRecovery”、文件“BulkNoggedRecover”处理184页。已为文件1上的数据库“BulkLoggedRecovery”和文件“BulkNoggedRecovery_log”处理了3个页面。RESTORE DATABASE在0.037秒内(39.392 MB/秒)成功处理了187页。已为文件1上的数据库“BulkLoggedRecovery”和文件“BulkNoggedRecover”处理0页。已为文件1上的数据库“BulkLoggedRecovery”和文件“BulkNoggedRecovery_log”处理了7页。备份集是由backup with CONTINUE_AFTER_ERROR使用损坏的数据写入的。RESTORE WITH CONTINUE_AFTER_ERROR已成功,但遇到了一些损坏。数据库中可能存在不一致。RESTORE LOG在0.013秒内成功处理了7个页面(4.018 MB/秒)。

清单6.12:使用恢复日志备份继续_后_错误.

这起到了作用,所以让我们研究一下恢复的数据库的状态。重新运行清单6.9,您将看到它被报告为在线、和SomeTable公司,的目标选择…进入存在,所以让我们看看是否有任何数据进入了表中(记住,页面分配被记录,页面内容没有记录)。

使用BulkLoggedRecoveryGO(开始)如果OBJECT_ID('dbo.SomeTable','U')不为空打印“SomeTable exists”选择*来自SomeTable消息824,级别24,状态2,行1SQL Server检测到基于逻辑一致性的I/O错误:pageid不正确(应为1:184;实际为0:0)。读取文件“C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\BulkLoggedRecovery.mdf”中偏移量为0x0000000170000的数据库ID 32中的页(1:184)时发生此错误。SQL Server错误日志或系统事件日志中的其他消息可能会提供更多详细信息。这是一种严重的错误情况,会威胁数据库的完整性,必须立即更正。完成完整的数据库一致性检查(DBCC CHECKDB)。这种误差可能由许多因素引起;有关详细信息,请参阅SQL Server联机丛书。

清单6.13:尝试读取SomeTable公司.

请注意,这是来自SQL Server 2008 Enterprise Edition的错误消息。你可能会在其他版本上看到不同的错误。无论如何,这看起来不太好;让我们看看DBCC检查DB表示数据库的状态。

DBCC CHECKDB(“BulkLoggedRecovery”),带NO_INFOMSGS、ALL_ERRORMSGS消息8921,级别16,状态1,行1检查已终止。收集事实时检测到故障。可能是tempdb空间不足或系统表不一致。检查以前的错误。

清单6.14:检查批量记录恢复具有DBCC检查DB.

不幸的是,这看起来一点也不好(TempDB并没有空间不足)。这里唯一明智的选择是再次恢复并放弃尾日志备份。这意味着在最后一次正常日志备份和故障点之间提交的任何事务都将丢失。

这是决定在中运行数据库时的另一个重要考虑因素散装_记录长期或短期恢复模型。FULL(满)恢复模型,尾部日志备份只需要访问事务日志。因此,即使MDF文件不可用,例如由于磁盘故障,我们仍然可以备份事务日志。然而,在散装_记录模型中,如果自上次日志备份以来发生了任何日志记录最少的操作,则意味着如果包含受日志记录最少操作影响的数据的数据文件变得不可用,我们将无法执行尾日志备份。原因是在中执行事务日志备份时散装_记录模型中,SQL Server必须将批量操作修改的所有实际数据块(即数据)以及事务日志条目备份到事务日志备份文件中。换句话说,SQL Server需要访问数据文件才能进行尾日志备份。

使用BULK_LOGGED的最佳实践

首先,检查数据库的SLA是否存在可接受的数据丢失风险。如果不允许数据丢失,则计划在FULL(满)恢复模型,以及这对日志增长的影响。如果您可以在SLA中指定的最大允许数据丢失范围内完成希望最小化日志记录的操作,那么您可以考虑使用散装_记录恢复。

黄金法则,当使用散装_记录恢复模型是在尽可能短的时间内使用它,并尽可能将日志记录最少的操作隔离到其自己的日志备份中。因此,在切换到之前立即进行事务日志备份散装_记录切换回时立即恢复和另一个事务日志备份FULL(满)恢复。这将确保在包含最少日志操作的日志间隔内尽可能少的时间和最少的事务数。

为了说明这是如何降低风险的,请考虑以下场景:

  • 凌晨1:00完整备份
  • 上午1:15事务日志备份1
  • 上午2:15事务日志备份2
  • 凌晨2:40切换到散装_记录,批量操作开始
  • 凌晨3:05批量操作结束
  • 凌晨3:10–故障–MDF不可用
  • 凌晨3:15事务日志备份3

在这种情况下,凌晨3点15分的日志备份将失败,随后进行尾部日志备份的尝试也将失败。我们所能做的就是恢复完整备份,然后再恢复前两个日志备份,这样我们将损失相当于55分钟的数据。

相反,如果我们采用了以下制度,我们的情况会好得多:

  • 凌晨1:00完整备份
  • 上午1:15事务日志备份1
  • 上午2:15事务日志备份2
  • 凌晨2:35事务日志备份3
  • 凌晨2:40切换到散装_记录,批量操作开始
  • 凌晨3:05批量操作结束
  • 凌晨3:05切换回FULL(满)并执行事务日志备份4
  • 凌晨3:10–故障–MDF不可用
  • 凌晨3:15事务日志备份5

在这里,3:15的日志备份也会失败,但我们随后可以执行尾日志备份,因为日志备份4确保实时日志中没有最低日志记录操作。然后,我们可以恢复完整备份、四个事务日志备份和尾日志备份,以在凌晨3点15分恢复到故障点。

即使有了这些预防性日志备份,最好在非工作时间执行任何日志记录最少的操作,而其他事务执行的次数很少(如果有的话)。这样,如果出现任何问题,我们可以简单地重放批量加载以恢复数据。

即使通过在每次批量操作前后进行额外的日志备份将风险降至最低,也不建议在批量日志记录模型。根据您的环境,很难完全控制谁可以执行日志记录最少的操作以及何时执行。请记住,任何表所有者都可以在该表上创建或重建索引;任何可以创建表的人也可以运行选择…进入声明。

最后,我们建议阅读这个数据加载性能指南(http://msdn.microsoft.com/en-us/library/dd425070.aspx),其中提供了许多关于实现高速批量数据修改的建议,并讨论了如何使用跟踪标志610测量从最小日志记录中产生的潜在好处。

总结

这个散装_记录恢复模型提供了一种执行数据加载和一些数据库维护操作(如索引重建)的方法,而无需通常在中产生的事务日志开销FULL(满)恢复模型,但仍保持日志链完整。这样做的缺点是,如果在批量操作期间或在批量操作的同一时间跨度内发生灾难,则可能会导致更大的数据丢失。换句话说,您将无法使用STOPAT公司选项时还原包含最少日志记录操作的日志文件。仍然可以恢复整个事务日志备份以向前滚动数据库,并且仍然可以恢复到不包含任何最低日志记录操作的后续日志文件中的某个时间点。但是,如果发生应用程序错误,或用户更改导致数据被删除,与最低日志记录的操作大约在同一时间段内,则无法在记录这些更改的日志中的特定时间点停止,以恢复删除的数据。

使用时批量日志记录恢复,请记住数据丢失的风险增加,并且仅在维护或数据加载操作期间使用恢复模型,而不将其用作默认恢复模型。

即使风险增加,这也是一个可行且有用的选项,也是DBA在规划数据加载或索引维护时应该考虑的问题。

致谢

非常感谢Shawn McGehee,《SQL Server备份和恢复(http://www.simple-talk.com/books/sql-books/ssql-backup-and-restore/)为数据库第页埃斯托尔此级别的部分。

本文是父楼梯的一部分SQL Server中事务日志管理的阶梯

资源

费率

5(2)

你对这篇文章的评价是5分之一。更改评级

分享

分享

费率

5(2)

你对这篇文章的评价是5分之一。更改评级