为什么在每晚备份的简单恢复模式下事务日志会继续增长


24

在立即将其标记为重复之前,我已阅读Mike Walsh的“ 为什么事务日志保持增长或空间不足?,但我认为这无法解决我的情况。我浏览了十几个类似的问题,但相关的问题大多只是说“重复”并指出了麦克的问题。

详细信息:我在SQL Server 2008 R2上有一堆约500MB的数据库,全部处于简单恢复模式(不是我的选择),每晚进行完整备份,并具有约200MB的数据文件和约300MB的日志文件。日志不会立即增长到300MB,而是会在几个月后缓慢增长。至少根据sp_who2和活动监视器,它们中的任何一个都没有打开的事务。如果我右键单击数据库并选择属性,它会告诉我大约有50MB可用空间。特别是在备份之后,整个日志是否不应该免费?在简单模式下,只要没有未完成的事务,日志是否不应该免费?

log_reuse_wait_descfrom sys.databases说“什么都没有”,根据上面提到的问题和答案,它说它不应该等待任何东西来重用空间。

如果我执行“ DBCC SHRINKFILE”,则日志文件会缩小到1MB,因此它愿意回收空间。我可以设置一些可以每周缩小日志并防止事情失控的事情,但是我对为什么SQL Server可以做到这一点感到困惑。

我可以理解是否有一些需要300MB记录的疯狂交易,但是我们没有做任何极端的事情,只是基本的OLTP。来自Mike的问题/答案:

简单恢复模型-通过上面的介绍,最简单的是首先讨论简单恢复模型。在此模型中,您要告诉SQL Server-可以使用事务日志文件进行崩溃和重新启动恢复(您确实没有选择。在这里查找ACID属性,应该很快就可以理解),但是一旦您没有,出于崩溃/重新启动恢复目的而不再需要它,请继续并重用日志文件。

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

它一直在说应该重新使用日志空间,但是随着几个月来的缓慢增长,似乎并没有。

我想念什么?是否可以阻止SQL Server将数据识别为“已强化”并释放日志?

(编辑) 行动后报告-又一点知识是危险的

在发现这是一个“普遍的问题”之后,感觉就像我对7个月前发生的事情以及我所学到的希望为其他人节省一些悲痛的事情做了解释。

首先,当您查看数据库的属性时,在SSMS中看到的可用空间就是数据文件中的可用空间。您可以通过在数据库上运行以下命令来查看此文件,然后发现SSMS报告的可用空间是FileSizeMB与UsedSpaceMB之间的差异:

SELECT
    DB.name,
    MF.physical_name,
    MF.type_desc AS FileType,
    MF.size * 8 / 1024 AS FileSizeMB,
    fileproperty(MF.name, 'SpaceUsed') * 8/ 1024 AS UsedSpaceMB,
    mf.name LogicalName
FROM
    sys.master_files MF
    JOIN sys.databases DB ON DB.database_id = MF.database_id
WHERE   DB.name = 'yourdatabasename'

这确实确认了在正常情况下我们仅使用了很少的日志空间(20MB或更小),但这导致了第二项...

第二,我对原木生长的感觉是随着时间的推移逐渐变慢。但是,实际上,日志在夜间迅速增长,负责为该第三方应用程序应用补丁的人正在应用补丁。修补程序是作为单个事务完成的,因此根据修补程序,200MB数据需要300MB日志。跟踪下来的关键是来自Aaron Bertrand的查询,网址https://sqlblog.org/2007/01/11/reviewing-autogrow-events-from-the-default-trace

DECLARE @path NVARCHAR(260);

SELECT 
    @path = REVERSE(SUBSTRING(REVERSE([path]), 
    CHARINDEX('\', REVERSE([path])), 260)) + N'log.trc'
FROM    sys.traces
WHERE   is_default = 1;

SELECT 
   DatabaseName,
   [FileName],
    SPID,
    Duration,
    StartTime,
    EndTime,
    FileType = CASE EventClass 
       WHEN 92 THEN 'Data'
       WHEN 93 THEN 'Log'
    END
FROM sys.fn_trace_gettable(@path, DEFAULT)
WHERE
    EventClass IN (92,93)
ORDER BY
    StartTime DESC;

这表明在某些晚上,客户不使用数据库时,日志正在增长。这导致了与应用补丁的人的对话以及谜底的答案。

再次感谢提供帮助的人,帮助我找到答案。


实际上,我自己在具有SIMPLE恢复模型的客户的一个站点数据库中观察到了类似的现象。日志还没有增长(但是无论如何),但是日志文件的已用空间每天晚上确实会增长一点点。它在数据库备份运行时发生。我还没有弄清楚是什么原因造成的,也没有弄清楚是不是问题。
RBarryYoung 2014年

Answers:


20

我们无法猜测是什么原因造成的,但是SQL Server不仅将日志文件增加到300 MB,还增加到300 MB,因为自上次收缩操作以来的某个时刻,它需要大量的日志空间(无论是由于某个大的单个事务还是许多较小的并发事务)。您必须跟踪日志文件增长事件(我在这里这里讨论过),以尝试缩小发生这种情况的时间或原因(同样,如果您将日志文件增长设置设置为300 MB左右,那么它将增长300 MB)只要它需要超过1 MB的空间来容纳活动的交易)。

无论如何,为什么您认为一旦日志文件达到300 MB,就需要收缩呢?实际上,您是否完整地阅读了麦克的问题的所有答案?日志文件不会自动缩小,因为将日志文件缩小到1MB(这样就可以在最大事务中再次增长)是完全浪费时间的。同时,您将如何处理所有这些可用空间?


我认为我们没有做任何需要300MB日志的事情,但是即使这样做,一旦完成,它也不会显示为数据库的可用空间吗?在SQL Server Management Studio中查看数据库上的属性时,大小是数据和日志的大小,我希望可用空间是数据和日志的可用空间。日志中的可用空间不会显示吗?它没有显示为免费,似乎仍在使用中,但是数据库上没有活动。
DerekCate

1
不,一旦完成,它不会自动变为可用空间。提交的事务不会被清零,它们的空间只是被标记为可供重用。
亚伦·伯特兰

1
@DerekCate“我认为我们没有做任何需要300MB日志的事情” ...您会惊讶的是,绑定事务日志的重用并不需要太多时间。不要从工作量的角度考虑它,因为这并非总是原因。
托马斯·斯金格2014年

好的,所以为了确认我正确理解了这一点,即使当前不需要300MB日志,也不会显示为可用空间,而是可以重用。在某个时候,它需要300MB的空间来处理某些事务。好吧,有新东西要研究。谢谢!
DerekCate 2014年

1
要考虑的另一件事:仅在日志已满70%时,才对简单恢复数据库的自动检查点进行排队。因此,根据时间的不同,您可能不需要太多的日志活动来导致增长。
保罗·怀特说GoFundMonica

6

您当前的所有测试(DBCC SHRINKFILElog_reuse_wait_desc)仅证明您现在正在适当地重用事务日志的虚拟日志文件。但是,当您的自动增长事件发生在事务日志文件上时,是对日志无法重用的一种反应。

通常,这不是一个持续的状况(正是您目前所看到的症状缺乏,现在看来确实如此)。即使在简单的恢复模型中,也有少数原因会导致此行为。

最好的选择是设置一个数据收集作业,以定期log_reuse_wait_desc为您的数据库提取,并定期将其记录在某个地方。然后,您应该能够对导致缺少日志重用的原因进行反向工程。

它一直在说应该重新使用日志空间,但是随着几个月来的缓慢增长,似乎并没有。

正如我上面所指出的,这不是一般的持续状态,导致缺乏事务日志重用(节省一些角落情况下,如制作粗糙的交易),所以你必须要找准当这时代发生。轻量级的诊断数据收集应该是一个好的开始。


如果他看到50MB的可用空间和300MB的日志,那么fn_DBLOG()会为他提供一些有关增加日志大小的见解?
肯尼斯·费舍尔

0

您是否在数据库上启用了自动收缩?和/或您是否已安排执行维护计划以执行索引重建?

自动收缩后再进行索引维护将产生大量日志。

如果存在数据库设计问题,例如GUID上的聚集索引,则索引维护本身也将产生大量的日志量。


数据库上未启用自动收缩功能,我们希望避免索引碎片brentozar.com/archive/2009/08/…。我们确实进行了每周完整性检查,但是我认为没有任何索引重建工作,我必须对此进行研究。除此之外,没有GUID,每个表都有一个标识列作为主键。
DerekCate 2014年

-3
 create table #dblog (Databasename varchar(100),
                     logsize float,
                     logspace%] float,
                     [Status] int)

 insert into #dblog
 EXEC ('DBCC sqlperf(logspace)') 

 select * from #dblog

 alter table #dblog 
 add [lgspace used GB] float;

 update #dblog 
 set [lgspace used GB ] = (logsize*[logspace%]/1024)

 update #dblog 
 set [logsize] =([logsize]/1024)

 alter table #dblog 
 drop column [Status];

 select * from #dblog

 drop table #dblog
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.