我不是 SQL 专家,每次我需要做一些超出基础的事情时,我都会想起这样一个事实。我有一个规模不大的测试数据库,但事务日志肯定是。如何清除事务日志?
确实应该为遇到意外增长而您不希望再次发生的情况保留使日志文件更小的情况。如果日志文件将再次增长到相同的大小,则暂时缩小它并不能完成很多工作。现在,根据您的数据库的恢复目标,这些是您应该采取的行动。
永远不要对数据库进行任何更改,除非确保在出现问题时可以恢复它。
(通过时间点恢复,我的意思是您关心能够恢复到除完整备份或差异备份之外的任何内容。)
大概您的数据库处于FULL恢复模式。如果不是,请确保它是:
FULL
ALTER DATABASE testdb SET RECOVERY FULL;
即使您定期进行完整备份,日志文件也会不断增长,直到您执行 日志 备份 - 这是为了保护您,而不是不必要地占用您的磁盘空间。根据您的恢复目标,您应该非常频繁地执行这些日志备份。例如,如果您的业务规则规定您可以承受在发生灾难时丢失不超过 15 分钟的数据,那么您应该有一个每 15 分钟备份一次日志的作业。这是一个脚本,它将根据当前时间生成带时间戳的文件名(但您也可以使用维护计划等来执行此操作,只是不要在维护计划中选择任何收缩选项,它们很糟糕)。
DECLARE @path NVARCHAR(255) = N'\\backup_share\log\testdb_' + CONVERT(CHAR(8), GETDATE(), 112) + '_' + REPLACE(CONVERT(CHAR(8), GETDATE(), 108),':','') + '.trn'; BACKUP LOG foo TO DISK = @path WITH INIT, COMPRESSION;
请注意,它\\backup_share\应该在代表不同底层存储设备的不同机器上。将这些备份到同一台机器(或使用相同底层磁盘的另一台机器,或同一物理主机上的不同 VM)并不能真正帮助您,因为如果机器发生故障,您就会丢失数据库 及其 备份。根据您的网络基础设施,在本地备份然后将它们转移到幕后的不同位置可能更有意义;在任何一种情况下,您都希望尽快将它们从主数据库机器上移除。
\\backup_share\
现在,一旦您运行了常规日志备份,将日志文件缩小到比现在被炸毁的任何东西更合理的东西应该是合理的。这并不 意味着 一遍SHRINKFILE又一遍地运行直到日志文件达到 1 MB - 即使您经常备份日志,它仍然需要容纳可能发生的任何并发事务的总和。日志文件自动增长事件代价高昂,因为 SQL Server 必须将文件归零(与启用即时文件初始化时的数据文件不同),并且用户事务必须在发生这种情况时等待。您希望尽可能少地执行这种增长-收缩-增长- 收缩例程,并且您当然不想让您的用户为此付费。
SHRINKFILE
请注意,您可能需要两次备份日志才能进行缩减(感谢 Robert)。
因此,您需要为您的日志文件提供一个实用的大小。如果您不了解更多有关您的系统的信息,这里没有人可以告诉您那是什么,但是如果您经常缩小日志文件并且它又一直在增长,那么一个好的水印可能比它的最大水印高 10-50% . 假设达到 200 MB,并且您希望任何后续自动增长事件为 50 MB,那么您可以通过以下方式调整日志文件大小:
USE [master]; GO ALTER DATABASE Test1 MODIFY FILE (NAME = yourdb_log, SIZE = 200MB, FILEGROWTH = 50MB); GO
请注意,如果日志文件当前 > 200 MB,您可能需要先运行:
USE yourdb; GO DBCC SHRINKFILE(yourdb_log, 200); GO
如果这是一个测试数据库,并且您不关心时间点恢复,那么您应该确保您的数据库处于SIMPLE恢复模式。
SIMPLE
ALTER DATABASE testdb SET RECOVERY SIMPLE;
将数据库置于SIMPLE恢复模式将确保 SQL Server 重新使用部分日志文件(基本上逐步淘汰非活动事务),而不是增长以保留 所有 事务的记录(就像FULL在备份日志之前恢复所做的那样)。CHECKPOINTevents 将有助于控制日志并确保它不需要增长,除非您在CHECKPOINTs 之间生成大量 t-log 活动。
CHECKPOINT
接下来,您应该绝对确保此日志增长确实是由于异常事件(例如,年度春季大扫除或重建最大索引),而不是由于正常的日常使用。如果您将日志文件缩小到小得离谱的大小,而 SQL Server 只需要再次增大它以适应您的正常活动,那么您得到了什么?您是否能够利用您只是暂时释放的磁盘空间?如果您需要立即修复,则可以运行以下命令:
USE yourdb; GO CHECKPOINT; GO CHECKPOINT; -- run twice to ensure file wrap-around GO DBCC SHRINKFILE(yourdb_log, 200); -- unit is set in MBs GO
否则,设置适当的大小和增长率。根据时间点恢复案例中的示例,您可以使用相同的代码和逻辑来确定合适的文件大小并设置合理的自动增长参数。
使用选项备份日志,TRUNCATE_ONLY然后SHRINKFILE。一方面,此TRUNCATE_ONLY选项已被弃用,并且在当前版本的 SQL Server 中不再可用。其次,如果您处于FULL恢复模式,这将破坏您的日志链并需要新的完整备份。
TRUNCATE_ONLY
分离数据库,删除日志文件,然后重新附加. 我无法强调这有多危险。您的数据库可能无法备份,可能会出现可疑情况,您可能必须恢复到备份(如果有的话)等等。
使用“收缩数据库”选项 。DBCC SHRINKDATABASE并且执行相同操作的维护计划选项是个坏主意,尤其是当您真的只需要解决日志问题时。DBCC SHRINKFILE使用或ALTER DATABASE ... MODIFY FILE(上面的示例)定位您要调整的文件并独立调整它。
DBCC SHRINKDATABASE
DBCC SHRINKFILE
ALTER DATABASE ... MODIFY FILE
将日志文件缩小到 1 MB 。这看起来很诱人,因为,嘿,SQL Server 会让我在某些情况下这样做,并查看它释放的所有空间!除非您的数据库是只读的(而且您应该使用 标记它ALTER DATABASE),否则这绝对会导致许多不必要的增长事件,因为无论恢复模型如何,日志都必须容纳当前事务。暂时释放该空间有什么意义,以便 SQL Server 可以缓慢而痛苦地收回它?
ALTER DATABASE
创建第二个日志文件 。这将为已填满磁盘的驱动器提供暂时的缓解,但这就像试图用创可贴修复被刺破的肺一样。您应该直接处理有问题的日志文件,而不是仅仅添加另一个潜在问题。除了将某些事务日志活动重定向到不同的驱动器之外,第二个日志文件实际上对您没有任何作用(与第二个数据文件不同),因为一次只能使用其中一个文件。Paul Randal 还解释了为什么多个日志文件会在以后给您带来麻烦。
与其将日志文件缩小到很小的数量并让它自己以很小的速率不断地自动增长,不如将它设置为相当大的大小(一个可以容纳最大并发事务集的总和的大小)并设置一个合理的自动增长设置为后备,因此它不必多次增长以满足单个事务,因此在正常业务操作期间它相对很少需要增长。
这里最糟糕的设置是 1 MB 增长或 10% 增长。有趣的是,这些是 SQL Server 的默认值(我曾抱怨并要求更改无济于事)——数据文件为 1 MB,日志文件为 10%。前者在当今时代太小了,后者每次都会导致越来越长的事件(例如,您的日志文件是 500 MB,第一次增长是 50 MB,下一个增长是 55 MB,下一个增长是 60.5 MB ,等等等等 - 在慢速 I/O 上,相信我,你会真正注意到这条曲线)。