如何最小化 SQL Server 中的日志操作以避免“日志已满”错误

Zer*_*ity 7 shrink transaction sql-server-2012 transaction-log

我在生产中有一个数据库,它不断地填充日志文件,它是一个数据仓库,并且有许多作业/查询正在运行。下面是我得到的错误

Msg 9002, Level 17, State 4, Line 7
The transaction log for database  is full due to 'ACTIVE_TRANSACTION'. 
Run Code Online (Sandbox Code Playgroud)

现在这是有道理的,我明白 SQL 无法执行操作,因为它的日志文件已满。我有两个日志文件

  • 启用无限制增长和自动增长的 D 盘 [D 盘大小 180 GB]
  • E盘静态大小[E盘120GB,日志文件大小:20GB]

我对这个问题做了一些研究,并找到了可能的解决方案:来源

  • 备份日志。
  • 释放磁盘空间,以便日志可以自动增长。
  • 将日志文件移动到具有足够空间的磁盘驱动器。
  • 增加日志文件的大小。
  • 在不同的磁盘上添加日志文件。
  • 完成或终止长时间运行的事务。

现在,假设我的空间有限(即 180 GB + 20 GB),我认为这对于 SIMPLE RECOVERY MODE 中的数据库来说已经足够了。我怎么可能发现这个问题并在它发生之前进行纠正?

复制

我试图通过使用以下设置创建新的示例数据库来复制此场景 在此处输入图片说明

和下面的查询以获取百万行并将它们插入表中

SET NOCOUNT ON;
DECLARE @SET_SIZE INT = 500000000;

CREATE TABLE dbo.Test500Million (N INT  PRIMARY KEY CLUSTERED NOT NULL);

;WITH T(N) AS (SELECT N FROM (VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) AS X(N))
,NUMS(N) AS (SELECT TOP(@SET_SIZE) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N FROM T T1, T T2, T T3, T T4, T T5, T T6, T T7, T T8, T T9)
INSERT INTO dbo.Test500Million(N)
SELECT N FROM NUMS;

DROP TABLE dbo.Test500Million 
Run Code Online (Sandbox Code Playgroud)

现在,在验证 sys.databases 并查看错误消息时,我同时找到了CHECKPOINTS & ACTIVE_TRANSACTION.

我的问题

  • 根据我的观察,我发现这只发生在插入语句而不是选择中。所以,我认为日志条目在任何情况下都只用于 INSERT/UPDATE 而不是用于 SELECT 语句。我对么?
  • 如何在插入更新记录时最小化日志记录?我已经有了简单的恢复模式。
  • 我发现在此期间的平均吞吐量从大约 25 MB 开始。到 1.2 MB。这是什么意思?
  • 除了增加磁盘空间之外,还有其他方法可以解决此问题吗?
  • 如果唯一的选择是缩小文件,那么我应该什么时候做?当任何活动事务处于 ON 状态时,我可以这样做吗?[生产环境]

如果您需要更多我可以收集的统计数据,请告诉我。

Sha*_*nky 7

•根据我的观察,我发现这种情况只发生在插入语句而不是选择中。所以,我认为日志条目在任何情况下都只用于 INSERT/UPDATE 而不是用于 SELECT 语句。我对么?

与插入、更新和删除等 DML 语句相比,不会记录此类 Select 语句。如果您看到fn_dblogfor select 语句的输出,它将不会有任何条目。但是 DML 语句会有很多条目。请注意。维护事务日志并在那里写入与事务相关的信息,以便在崩溃恢复或恢复期间 SQL Server 可以知道哪些事务已提交和哪些未提交,阅读它可以使数据库保持一致状态,这就是为什么日志如此必要. 没有事务日志恢复是不可能的

出于所有实际目的,每个事务都记录在 SQL Server 中。所以你不能有一个场景,你运行一个事务并且事务日志中没有记录任何内容。您无法选择禁用 SQL Server 中的日志记录。我建议您阅读SQL Server 中的日志记录和恢复

•如何在插入更新记录时最小化日志记录?我已经有了简单的恢复模式

您误以为在简单恢复模型中不会发生日志记录,它确实会发生,但是在事务提交时事务日志被截断,并且为事务生成的日志使用的空间被重新利用。事实上,简单恢复中的日志记录几乎与完全恢复相同,不同之处在于日志截断发生的时间。是的,您可以在批量日志恢复模型中为某些命令进行最少的日志记录。对于 rest 命令,即使在批量记录的恢复模型中,日志记录也会已满。

•我发现在此期间的平均吞吐量从大约 25 MB 上升到 25 MB。到 1.2 MB。这是什么意思?

我无法理解这一点,请您解释一下。

• 除了增加磁盘空间之外,还有其他方法可以解决此问题吗?

正如已经建议的那样,如果您保持@SET_SIZE INT = 500000000(即使它是虚拟的)为什么这么高的限制,您最有可能面临问题。你能不能把它减少到 500000 并查看日志文件的行为。确保日志文件的自动增长以 MB 为单位并设置为一些合理的值。分批进行交易。最后,如果您阅读为什么事务日志不断增长或空间不足,您可以获得一些好主意。

•如果只能选择缩小文件,那我应该什么时候做?当任何活动事务处于 ON 状态时,我可以这样做吗?[生产环境],为指导我,但我需要释放空间。我有一个每天处理数百万数据的大型数据仓库

请不要缩小任何数据或日志文件。我不会推荐它。如果您真的想缩小一次以回收空间并且除了缩小之外别无选择,您不妨尝试一下。但再次记住,在完成收缩后,您必须重建所有碎片索引。您可以尝试本文中 Paul 给出的方法,方法说不要收缩并给出收缩的替代方案。

您只能缩小日志文件一次,但请记住日志文件的增长是因为您运行了迫使它增长的事务,所以它基本上是您的错误而不是事务日志文件。为什么不为日志文件预先分配一些空间来避免自动增长事件,而不是整个增长和缩小过程

另一件事

在此处输入图片说明

上面的配置很糟糕。数据文件的 1 MB 自动增长必然会导致问题。要设置正确的值,请阅读文章Autogrowth settings。这将帮助您计算正确的自动增长设置。