为什么事务日志持续增长或空间不足?


264

在大多数论坛和整个网络中,这似乎是一个常见问题,在这里以多种格式询问,通常听起来像这样:

在SQL Server中-

  • 事务日志变得如此之大的一些原因是什么?
  • 为什么我的日志文件这么大?
  • 有什么方法可以防止出现此问题?
  • 当我使自己的潜在原因步入正轨并希望将事务日志文件调整为正常大小时,该怎么办?

4
真正的简短答案是:将数据库置于“ 简单”模式(而非“ 完全”模式)。如果您在每晚完整备份之间的白天没有进行多次事务日志备份:则不需要完全模式。
伊恩·博伊德

@IanBoyd-当然,这是最简单的答案。但是,关键是要明白这意味着什么。我在回答中提到了这一点。可悲的是,太多的人要么从不解决这个问题,要么只是在不了解原因的情况下转向简单。我将修改我的答案打在简单模式早一点在里面,虽然..
迈克·沃尔什

如果将数据库设置为完全模式,则先进行完全备份,然后再备份事务日志。这应减小LDF文件的大小。如果不执行收缩操作,也应这样做(不建议收缩)。文件仍然很大,请检查为LDF文件设置的初始大小。在我的情况下,初始LDF文件大小很大。
user9516827

@ user9516827进行完整备份然后再进行日志备份绝对不会减少日志文件的大小-日志备份只会使文件中的已用空间可供重用。而且,如果您不做任何更改,它只会再次发生,因此缩小对于使其稍后再增长毫无意义。
亚伦·伯特兰

Answers:


321

简短的答案:

您可能正在运行一个运行时间很长的事务(索引维护?是大批删除还是更新?),或者您处于“默认”(默认情况下更多信息)恢复模式,Full并且没有进行日志备份(或没有足够频繁地服用它们)。

如果是恢复模型问题,则简单的答案可能是:Simple如果您不需要时间点恢复和常规日志备份,则切换到恢复模式。但是,许多人在回答问题时却不了解恢复模型。请继续阅读以了解其重要性,然后再决定要做什么。您也可以开始进行日志备份并保持Full恢复状态。

可能还有其他原因,但这是最常见的原因。该答案开始深入探讨最常见的两个原因,并为您提供了一些原因以及背后原因的背景信息,并探讨了其他一些原因。


更长的答案: 哪些情况可能导致日志持续增长?原因有很多,但是通常这些原因有以下两种模式:对恢复模型有误解,或者有长期运行的事务。继续阅读以获取详细信息。

首要原因1/2:不了解恢复模型

处于完全恢复模式并且不进行日志备份 -这是最常见的原因-绝大多数遇到此问题的人都是。

尽管此答案不是对SQL Server恢复模型的深入探讨,但是恢复模型的主题对于此问题至关重要。

在SQL Server中,有三种恢复模型

  • Full
  • Bulk-Logged
  • Simple

Bulk-Logged现在我们将忽略它,我们会说它是一个混合模型,并且该模型中的大多数人都出于某种原因在那儿并且了解恢复模型。

我们关心的两个和他们的困惑是广大的有这个问题的人病例的原因是SimpleFull

中场休息:总体恢复

在讨论恢复模型之前:让我们先讨论恢复。如果您想进一步探讨该主题,请阅读Paul Randal的博客以及您想要的更多帖子。但是对于这个问题:

  1. 崩溃/重新启动恢复
    事务日志文件的目的之一是崩溃/重新启动恢复。用于在崩溃或重新启动之前完成的工作的前滚和后滚(前滚/重做),以及在崩溃或重新启动后已开始但未完成的工作(后滚/撤消)。事务日志的工作是查看事务已开始但从未完成(在提交事务之前发生了回滚或崩溃/重新启动)。在这种情况下,恢复过程中日志的工作是说“嘿..这还没有真正完成,让我们回滚”。这也是日志的工作,以确保您确实完成了某些工作,并告知客户端应用程序已完成(即使尚未将其硬化到数据文件中),并说重新启动后,“嘿,这确实发生了,让我们向前发展,让它像应用程序认为的那样。” 现在还有更多,但这是主要目的。

  2. 时间点恢复
    事务日志文件的另一个目的是使我们能够恢复到由于数据库中的“ oops”导致的时间点,或者在发生硬件故障时保证恢复点的能力。涉及数据库的数据和/或日志文件。如果此事务日志包含已开始和完成以进行恢复的事务记录,则SQL Server可以并且确实会使用此信息将数据库恢复到问题发生之前的位置。但这并不总是我们可用的选择。为此,我们必须使数据库具有正确的恢复模型,并且必须进行日志备份

恢复模型

关于恢复模型:

  • 简单恢复模型
    因此,通过上面的介绍,最简单地讨论Simple Recovery模型。在此模型中,您告诉SQL Server:“我很好,可以使用事务日志文件进行崩溃并重新启动恢复...”(您在那里真的没有选择。查找ACID属性,应该很快就可以理解。)“ ...但是一旦出于崩溃/重新启动恢复的目的不再需要它,请继续并重用日志文件。”

    SQL Server在简单恢复中侦听此请求,并且仅保留进行崩溃/重新启动恢复所需的信息。一旦SQL Server确定它可以恢复,因为数据已被硬化到数据文件(或多或少),则已硬化的数据在日志中将不再是必需的,并且被标记为截断的-这意味着它将被重新使用。

  • 完全恢复模型
    使用Full Recovery,您将告诉SQL Server您希望能够恢复到特定的时间点,只要您的日志文件可用或恢复到日志备份所涵盖的特定的时间点即可。在这种情况下,当SQL Server达到可以安全地截断简单恢复模型中的日志文件的程度时,它将不会执行此操作。相反,它可以使日志文件继续增长并允许其继续增长,直到在正常情况下进行日志备份(或日志文件驱动器上的空间不足)为止

从“简单”切换到“完整”会出现问题。

这里有规则和例外。我们将在下面深入讨论长期运行的事务。

但是要记住完全恢复模式的一个警告是:如果您只是切换到Full Recovery模式,但是从不进行初始完全备份,则SQL Server将不会接受您成为Full Recovery模型的请求。您的事务日志将继续按原样运行,Simple直到您切换到完全恢复模型并开始使用Full Backup

没有日志备份的完全恢复模型是不好的。

因此,这是不受控制的日志增长的最常见原因?答:处于完全恢复模式,没有任何日志备份。

这种情况发生的所有的时间的人。

为什么这是一个常见错误?

为什么总是发生这种情况?因为每个新数据库都通过查看模型数据库来获得其初始恢复模型设置。

模型的初始恢复模型设置始终为Full Recovery Model-直到且除非有人进行更改。因此,您可以说“默认恢复模型”为Full。许多人没有意识到这一点,因此他们的数据库在运行Full Recovery Model时没有日志备份,因此事务日志文件比所需的大得多。这就是为什么在默认设置不适用于您的组织及其需求时更改默认设置很重要的原因。

日志备份太少的完全恢复模型是不好的。

您也可以通过不经常进行日志备份来使自己陷入困境。
每天进行一次日志备份听起来不错,它使还原所需的还原命令更少,但是请记住上面的讨论,在您进行日志备份之前,日志文件将继续增长。

如何找出所需的日志备份频率?

您需要考虑两个方面来考虑日志备份频率:

  1. 恢复需求 -希望这应该是第一位的。如果存放事务日志的驱动器损坏或严重损坏,从而影响了日志备份,那么会丢失多少数据?如果该数字不超过10-15分钟,那么您需要每10-15分钟进行一次日志备份,直到讨论结束。
  2. 日志增长 -如果您的组织由于能够轻松地重新创建当天而丢失更多数据,则可以以少于15分钟的频率进行日志备份。也许您的组织每4小时就可以了。但是您必须查看4个小时内产生了多少交易。允许日志在这四个小时内持续增长是否会使日志文件太大?这是否意味着您的日志备份会花费太长时间?

最高原因2/2:长期交易

“我的恢复模型很好!日志还在增长!

这也可能是不受控制和不受约束的日志增长的原因。不管恢复模型如何,它通常都会出现为“但是我处于简单恢复模型中-为什么我的日志仍在增长?!”

原因很简单:如上所述,如果SQL出于恢复目的而使用该事务日志,则它必须回顾事务的开始。

如果您的事务需要很长时间或进行了很多更改,则对于仍在打开的事务中或自该事务启动以来已开始的任何更改,日志无法在检查点上截断。

这意味着一个大的删除操作,即在一条delete语句中删除数百万行是一项事务,在完成整个删除操作之前,日志无法执行任何截断操作。在中Full Recovery Model,此删除记录在日志中,并且可能是很多日志记录。在维护时段内,与索引优化工作相同。这也意味着不良的事务管理以及不监视和关闭未完成的事务确实会严重损害您和您的日志文件。

这些长期运行的交易我该怎么办?

您可以通过以下方式在这里保存自己:

  • 适当调整日志文件的大小以解决最坏的情况-例如维护或已知的大型操作。当您增加日志文件时,您应该参考Kimberly Tripp的这份指南(以及她发送给您的两个链接)。在这里,正确调整大小至关重要。
  • 观察您的交易使用情况。不要在应用程序服务器中启动事务,不要与SQL Server进行长时间的对话,否则可能会导致打开时间太长。
  • 监视DML语句中的隐式事务。例如:UPDATE TableName Set Col1 = 'New Value'是一笔交易。我没有在BEGIN TRAN那儿放,也不必在那儿放,它仍然是一项事务,完成后会自动提交。因此,如果对大量行进行操作,请考虑将这些操作分批处理为更易于管理的块,并提供日志时间进行恢复。或考虑合适的尺寸来处理。或者在批量加载窗口期间研究更改恢复模型。

这两个原因也适用于日志传送吗?

简短的回答:是的。下面的答案更长。

问题:“我正在使用日志传送,因此我的日志备份是自动化的……为什么我仍然看到事务日志增长?”

答:继续阅读。

什么是日志传送?

日志传送就像听起来一样-您将事务日志备份传送到另一台服务器以进行灾难恢复。进行了一些初始化,但是之后的过程非常简单:

  • 备份一台服务器上的日志的作业,
  • 复制该日志备份的作业,以及
  • 在目标服务器上进行恢复而不进行恢复(NORECOVERYSTANDBY)的作业。

如果您没有按计划进行工作,还有一些工作可以监视和警告。

在某些情况下,您可能只想每天或每三天或每周一次进行日志传送还原。那也行。但是,如果您对所有作业(包括日志备份和复制作业)进行此更改,则意味着您正在等待所有时间进行日志备份。这意味着您将有大量的日志增长-因为您处于没有日志备份的完全恢复模式下 -可能还意味着要复制整个日志文件。您应该只修改还原作业的日程表,并让日志备份和副本更频繁地发生,否则您将遭受此答案中描述的第一个问题的困扰。


通过状态码进行常规故障排除

除了这两个原因之外,还有其他一些原因,但这是最常见的。无论原因为何,都有一种方法可以分析这种无法解释的日志增长/缺少截断的原因,并查看其原因。

通过查询sys.databases目录视图,您可以看到描述您的日志文件可能在截断/重用中等待原因的信息。

有一个log_reuse_wait用原因码的查找ID 调用的log_reuse_wait_desc列,以及用等待原因描述的列。网上参考书籍中的大部分原因(您可能会看到的原因,以及我们可以解释的原因。缺少的原因是已停用或内部使用),其中有一些有关等待时间的注意事项斜体

  • 0 =没什么
    听起来像..不应该等待

  • 1 =检查点
    等待检查点发生。这应该发生,并且应该没问题-但在某些情况下,请在此处查找以后的答案或进行修改。

  • 2 =日志备份
    您正在等待日志备份发生。您已经安排好了它们,并且很快就会发生,或者您遇到了这里描述的第一个问题,现在您知道如何解决它了

  • 3 =活动备份或还原
    数据库上正在运行备份或还原操作

  • 4 =活动事务
    有一个活动事务需要先完成(方式- ROLLBACKCOMMIT),然后才能备份日志。这是此答案中描述的第二个原因。

  • 5 =数据库镜像
    在高性能镜像情况下镜像落后或处于某些延迟下,或者由于某种原因镜像被暂停

  • 6 =复制
    复制可能会导致此问题-例如日志读取器代理未运行,数据库认为该标记已被标记为不再存在复制以及其他各种原因。您还可以看到此原因,这是完全正常的,因为您正在查看正确的时间,就像日志读取器正在消耗事务一样

  • 7 =创建数据库快照
    您正在创建数据库快照,如果在创建快照的适当时机会看到此信息

  • 8 =日志扫描
    我还没有遇到与此相关的问题。如果您看够了足够长的时间和频率,便可以看到这种情况的发生,但这并不是造成事务日志过度增长的原因。

  • 9 = AlwaysOn可用性组辅助副本正在将此数据库的事务日志记录应用于相应的辅助数据库。 关于最清晰的描述


1
页面拆分将增加日志记录。根据我的经验,在很多情况下尚未解决的可能需要频繁缩小的大幅增长的一个重要原因(根据我的经验)将是使用适当的索引选择,包括适当的FillFactor mgmt。我使用以下设置,仔细观察。FF设置:(0/100)个表具有高读/低写,(90)稍作修改,(80)中读/低中写,(70)高写,(60)我很难达到水平或其他问题可能是错误的。然后使用正确的索引管理计划匹配的数据量。
SnapJag 2015年

113

由于我对Stack Overflow上的所有答案都不是真正满意的,包括投票最多的建议,并且由于我想解决Mike的答案不正确的几件事,我想我会提供我的输入也在这里。我也把这个答案的副本放在了那里。

对于遇到意外增长(您不希望再次发生这种情况)的情况,应该真正减小日志文件的大小。如果日志文件将再次增大到相同的大小,则暂时缩小将不会有太多效果。现在,根据数据库的恢复目标,这些是您应该执行的操作。

首先,进行完整备份

如果发生问题,请务必对数据库进行任何更改,否则请确保无法还原数据库。

如果您关心时间点恢复

(通过时间点恢复,我的意思是您关心的是能够还原到除完整备份或差异备份以外的任何内容。)

大概您的数据库处于FULL恢复模式。如果没有,请确保它是:

ALTER DATABASE yourdb SET RECOVERY FULL;

即使您进行常规的完整备份,日志文件也会不断增长,直到执行日志备份为止-这是为了保护您,而不是不必要地吞噬了磁盘空间。根据恢复目标,您应该非常频繁地执行这些日志备份。例如,如果您有一条业务规则规定在发生灾难时可以承受不少于15分钟的数据丢失损失,则您应该有一份每15分钟备份一次日志的作业。这是一个脚本,它将根据当前时间生成带有时间戳的文件名(但是您也可以使用维护计划等来执行此操作,只是不要在维护计划中选择任何收缩选项,它们太糟糕了)。

DECLARE @path NVARCHAR(255) = N'\\backup_share\log\yourdb_' 
  + CONVERT(CHAR(8), GETDATE(), 112) + '_'
  + REPLACE(CONVERT(CHAR(8), GETDATE(), 108),':','')
  + '.trn';

BACKUP LOG foo TO DISK = @path WITH INIT, COMPRESSION;

请注意,它\\backup_share\应该在代表不同基础存储设备的另一台计算机上。将这些备份到同一台计算机(或使用同一基础磁盘的另一台计算机,或同一物理主机上的另一台VM)并不能真正帮助您,因为如果计算机崩溃,您将丢失数据库它的备份。根据您的网络基础架构,在本地备份然后将其转移到幕后的其他位置可能更有意义。无论哪种情况,您都希望尽快将它们从主数据库计算机中删除。

现在,一旦您运行了常规的日志备份,就应该将日志文件压缩到比现在炸毁的文件更合理的大小。但这并不意味着运行SHRINKFILE,直到日志文件为1 MB一遍又一遍-即使你经常备份日志,它仍然需要适应可能出现的任何并发事务的总和。日志文件自动增长事件非常昂贵,因为SQL Server必须将文件归零(与启用即时文件初始化时的数据文件不同),并且用户事务必须等待这种情况发生。您希望尽可能少地执行此增长-收缩-增长-收缩例程,并且您当然不想让用户为此付费。

请注意,可能需要收缩两次日志才能进行收缩(感谢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恢复模式。

ALTER DATABASE yourdb SET RECOVERY SIMPLE;

将数据库置于SIMPLE恢复模式将确保SQL Server重用日志文件的某些部分(实质上逐步淘汰不活动的事务),而不是增加以保留所有事务的记录(就像FULL恢复一样,直到备份日志为止)。CHECKPOINT事件将有助于控制日志,并确保它不需要增长,除非您在CHECKPOINTs 之间生成了很多t-log活动。

接下来,您应该绝对确保此日志增长确实是由于异常事件(例如,每年一次的春季大扫除或重建最大的指标),而不是由于日常的日常使用。如果将日志文件缩小到一个可笑的小尺寸,而SQL Server只需要再次增大它以适应您的正常活动,那么您获得了什么?您是否能够利用您只是暂时释放的磁盘空间?如果需要立即修复,则可以运行以下命令:

USE yourdb;
GO
CHECKPOINT;
GO
CHECKPOINT; -- run twice to ensure file wrap-around
GO
-- 200 MB
DBCC SHRINKFILE(yourdb_log, 200);
GO

否则,请设置适当的大小和增长率。按照时间点恢复情况下的示例,您可以使用相同的代码和逻辑来确定合适的文件大小并设置合理的自动增长参数。

一些你不想做的事

  • 使用TRUNCATE_ONLYoption 备份日志,然后选择SHRINKFILE。例如,此TRUNCATE_ONLY选项已被弃用,并且在当前版本的SQL Server中不再可用。其次,如果您处于FULL恢复模式,这将破坏您的日志链,并需要新的完整备份。

  • 分离数据库,删除日志文件,然后重新附加。我不能强调这有多危险。您的数据库可能无法备份,可能会被怀疑备份,可能必须还原到备份(如果有),等等。

  • 使用“缩小数据库”选项DBCC SHRINKDATABASE使用维护计划选项执行相同操作是个坏主意,尤其是在您只需要解决日志问题的情况下。定位您要调整的文件,并使用DBCC SHRINKFILEALTER DATABASE ... MODIFY FILE(上述示例)分别进行调整。

  • 将日志文件缩小到1 MB。这看起来很诱人,因为,在某些情况下,SQL Server将允许我执行此操作,并查看它释放的所有空间!除非您的数据库是只读的(并且应该使用标记ALTER DATABASE),否则这绝对会导致许多不必要的增长事件,因为无论恢复模式如何,日志都必须容纳当前事务。暂时释放该空间的目的是什么,以便SQL Server可以缓慢而痛苦地收回该空间?

  • 创建第二个日志文件。这将暂时缓解已满磁盘的驱动器,但这就像试图用创可贴修复被刺破的肺部一样。您应该直接处理有问题的日志文件,而不是仅添加另一个潜在的问题。除了将某些事务日志活动重定向到其他驱动器之外,第二个日志文件确实对您没有任何作用(与第二个数据文件不同),因为一次只能使用其中一个文件。保罗·兰德尔(Paul Randal)也解释了为什么以后会有多个日志文件咬你

主动

与其将您的日志文件缩小到少量并让它自己不断以很小的速度自动增长,不如将它设置为一个相当大的大小(一个可以容纳您最大并发事务集的总和)并设置一个合理的自动增长设置为后备,这样它就不必多次增长就可以满足单个交易,因此在正常业务运营期间必须不断增长的情况相对很少。

这里最糟糕的设置是1 MB增长或10%增长。有趣的是,这些是SQL Server的默认值(我抱怨过,要求更改无用)-数据文件1 MB,日志文件10%。前者在当今时代太小了,后者每次导致的事件越来越长(例如,您的日志文件为500 MB,第一个增长为50 MB,下一个增长为55 MB,下一个增长为60.5 MB等等。-在慢I / O上,相信我,您会真正注意到此曲线)。

进一步阅读

请不要在这里停下来;尽管您看到的有关缩小日志文件的许多建议本质上都是不好的,甚至可能造成灾难性的影响,但有些人更关心数据的完整性而不是释放磁盘空间。


27

您还可以查看日志文件的内容。为此,可以使用未记录fn_dblog的事务日志读取器,例如ApexSQL Log

它不显示索引重组,但它显示了所有DML和各种DDL事件:ALTERCREATEDROP,触发启用/禁用,授予/撤销权限,对象重命名。

ApexSQLLogProject.temp-ApexSQL.log

免责声明:我是ApexSQL的支持工程师


5

对于几乎所有日志增长并填满磁盘的DBA,这都是最常面临的问题。

•事务日志变得如此之大的一些原因是什么?

  1. 长期活跃交易
  2. 高日志记录事务,例如索引重建,重新组织,批量插入,删除等。
  3. 已配置的任何HA(例如复制,镜像)都保留日志,并且不允许其释放日志空间

•为什么我的日志文件这么大?

检查表中的log_reuse_wait_desc列sys.databases以了解什么导致日志被截断:

select name, log_reuse_wait_desc 
from sys.databases

•有什么方法可以防止此问题发生?

日志备份将帮助您控制日志的增长,除非有某些因素阻止了日志的重复使用。

•当我跟踪潜在原因并希望将事务日志文件调整为正常大小时,该怎么办?

如果您确定了真正的原因,那么请尝试进行相应的修复,如下页所述。

https://www.brentozar.com/archive/2016/03/my-favorite-system-column-log_reuse_wait_desc/

除非有特殊情况,否则安排适当的日志备份是应对日志增长的最佳方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.