关于事务日志及其在 SQL Server 中的截断
本文介绍了关于事务日志行为和日志截断的基本信息。
引言
关于 SQL Server 中事务日志的截断,时不时会有各种讨论出现。日志截断通常被当作解决日志文件已满或即将填满问题的办法。虽然截断日志和收缩日志文件确实可以帮助继续使用数据库,但真正的问题 另有原因,在截断之前和之后都应采取适当的措施。
那么,什么是事务日志?
顾名思义,事务日志用于存储有关正在进行和已完成的事务及其状态的信息。从恢复的角度来看,这是数据库中最重要的一组文件之一。借助事务日志中的信息,可以在发生灾难时将数据库恢复到最新状态。此外,如果需要,还可以将数据库恢复到某个特定的时间点,而忽略之后的操作。
日志文件(或日志文件组)是循环使用的。这意味着日志文件从头开始填充,当达到文件末尾时,日志信息将从文件开头重新开始写入。这种情况仅发生在文件开头有 可用空间 时。如果文件中没有空间,文件会扩大,如果可能的话。文件扩展受文件自动增长设置以及剩余磁盘空间的限制。
日志文件的内容在逻辑上分为三类:
- 已用部分
包含已写入事务日志但可以删除的日志记录。 - 活动部分
这是事务日志中由最旧的活动事务定义的部分。在事务仍然处于活动状态时,此信息无法删除。 - 未使用部分
这是空闲空间。
当从事务日志中删除日志记录时,已用部分会被清空。活动部分仍然保留,例如用于可能的撤销等。日志记录通过检查点或日志备份操作从日志中删除。
恢复模式
通过恢复模式,管理员基本上定义了在发生灾难时可以恢复什么。有三种不同的恢复模式:完整 (Full)、大容量日志记录 (Bulk-logged) 和简单 (Simple)。本文简要讨论完整和简单恢复模式。
简单恢复模式
简单恢复模式是最“容易”使用的。从备份的角度来看,每隔一段时间都需要运行一次完整备份。在此上下文中,完整备份指的是整个数据库备份或同时备份所有读写文件。恢复时,数据库的内容将恢复到备份结束时的状态。在简单恢复模式下,这是“最好”的结果,因此足够频繁地执行完整数据库备份至关重要。
从事务日志的角度来看,使用简单恢复模式意味着:
- 每次发生检查点时,事务日志(可清除的部分)都会被清空。
- 无法执行日志备份。
因此,如果使用简单恢复模式,事务日志会频繁清空,不应该会增长太多。缺点当然是无法进行实际的恢复,只能恢复数据库。
完整恢复模式
在完整恢复模式下,最重要的区别是,当发生检查点时,事务日志不会被清空。相反,随着数据库中发生更改,新的日志记录会不断累积到事务日志中。清空事务日志的正确方法是定期执行成功的日志备份。成功的日志备份操作会在日志备份操作结束时清空事务日志的已用部分。与前面提到的检查点不同的是,现在数据更改已通过备份得到保护。
日志增长过多
现在这是经常被提及的问题。日志不断增长,或者已经增长得过大以至于无法容忍。根据前面的描述,您应该首先检查恢复模式。因此,这里有一个小的清单:
- 您是否正在使用简单恢复模式?
- 事务日志应在检查点自动清空。
- 您是否有长时间运行的事务?
请记住,日志的活动部分从第一个活动事务的开头开始,即使它已经存在了一周。这部分日志无法清空。 - 您是否正在使用完整恢复模式?
- 您是否已定义事务日志备份?
- 事务日志备份是否已成功?
- 事务日志备份运行的频率是否足够?
- 与之前相同的问题,您是否有运行时间过长的事务?
这些问题应该能让您更清楚地了解实际导致这种情况的原因。
如果日志文件没有满,但已经增长过大,首选的选项不是截断它。相反,如果您正在使用简单恢复模式,您应该调查长时间运行的事务,并查找使用数据库的应用程序中可能的缺陷。
如果您正在使用完整恢复模式,那么请关注事务日志备份,可能它们存在问题。当然,一个自然的问题是,您是否需要完整恢复模式?如果这是一个生产环境,答案很可能是肯定的。但是,如果您不需要恢复到最后一个时间点(或特定时间点)的能力,那么您可以考虑将恢复模式更改为简单。
日志已满
这是一个更严重的情况,尤其是在您使用完整恢复模式时。当日志变满且无法再增长时,通常会引发 错误 9002
。例如:
Msg 9002, Level 17, State 4, Line 3 The transaction log for database 'Database name' is full due to 'ACTIVE_TRANSACTION'.
这意味着,在事务日志中有足够的可用空间之前,无法成功执行改变数据库状态的操作。但是,这也意味着不能保证所有必要的信息都已记录到事务日志中。
之前的清单也适用于此情况,但由于日志确实已满,您还应该检查日志文件的自动增长设置。它是否已正确定义,或者是否应该让日志增长更多?
无论决定让日志增长更多还是不增长,在这种情况下都可以截断日志。在早期版本的 SQL Server 中,这是通过发出特殊的日志备份命令来完成的。
BACKUP LOG WITH TRUNCATE_ONLY;
这基本上与简单恢复模式下的检查点所做的事情相同;可以删除的内容将被丢弃以获得可用空间。
在 SQL Server 2008 及更高版本中,此命令已被弃用,取而代之的是,您必须暂时将恢复模式从完整更改为简单。使用 Transact-SQL 可以通过发出以下命令来完成:
ALTER DATABASE <database name> SET RECOVERY SIMPLE;
截断日志(无论以何种方式)也意味着在完整恢复模式下,日志链被破坏。嗯,实际上,在日志变满的那一刻,日志链就已经被破坏了。但即便如此,在完整恢复模式下,您也不能就此停止。
为了能够将数据库恢复到最后一个时间点,日志链必须是完整的。日志链意味着所有改变数据库文件内容的操作都已记录在事务日志中,因此可以在日志备份中找到它们。使用日志备份,日志记录可以用来恢复数据库。由于事务日志已满,很可能丢失了一些东西,并且由于日志被截断,肯定丢失了一些东西。
后续步骤
如果您之前使用的是完整恢复模式,并将其切换为简单以清除日志,请不要忘记将其切换回完整,除非您已决定从此以后使用简单恢复模式。要在新版本的 SQL Server 中将恢复模式设置为完整,请发出以下命令:
ALTER DATABASE <database name> SET RECOVERY FULL;
截断事务日志后,请考虑是否应该收缩日志文件。如果您使用的是完整恢复模式并决定让文件稍微增长一些,那么收缩日志就没有意义了。另一方面,如果日志备份运行得更频繁,那么为了获得更多磁盘空间,收缩文件可能是有意义的。
特别是,如果决定永久从完整恢复模式更改为简单恢复模式,日志可能不会增长那么多,因此收缩是合理的。
使用 DBCC 命令可以收缩日志文件。简而言之,要收缩日志,请发出以下命令:
DBCC SHRINKFILE (<name of the logfile>, <target size>)
最后,也是最重要的一步是确保您的备份历史记录处于有效状态。如前所述,如果使用完整恢复模式,为了能够恢复数据库,您需要一个有效的完整数据库备份,在此基础上可以应用日志备份。现在,由于之前的日志备份链在日志变满的那个点上是不可用的,因此您需要一个新的恢复起点。
通常最简单的方法是执行一个新的完整数据库备份。如果您有一个预定义的作业来执行此任务,您可以运行该作业或手动发出命令。
在成功完成所有这些步骤之后,您应该再次处于有效状态,并且能够安睡。一如既往,当发生特殊情况或您对备份有任何疑问时,建议测试从最新备份恢复,以验证其完整性。
参考文献
有关本文中提到的命令的更多信息
历史
- 2012年5月8日:创建。
- 2012年8月9日:进行了少量修正和格式调整。