数据库日志文件结构对数据库还原时间的影响


情景描述

我们经常遇到数据库需要很长时间才能恢复的情况。一个常见的场景是,在 SQL Server 重新启动之后,恢复过程必须前滚或回滚数据库的多个事务。然而,你可能还会看到以下症状之一,这些症状可能导致数据库需要很长时间才能恢复(即使日志文件中没有很多事务)。

  1. 从重新启动 SQL Server 或备份或还原或附加/分离或自动关闭这些状态启动数据库。
  2. 在事务复制中使用数据库时,日志读取进程延迟:日志读取进程的读取器线程负责扫描事务日志,以确定需要复制哪些事务。

原因

如果日志文件增长了几次(通常是由于非常小的自动增长设置),就会发生这种情况。结果,日志将有数千到几百万的 VLFs 你可以在 事务日志物理体系结构 中阅读更多关于 VLFs 的信息)。恢复数据库的第一阶段称为发现,在实际恢复开始之前,所有 VLFs 都被扫描(以串行和单线程方式)。由于这种情况发生在分析阶段之前,因此没有消息指示 SQL Server 错误日志中的进度。根据 VLFs 的数量,这个初始发现阶段可能需要几个小时,即使日志中没有需要处理的事务。

收集以下信息以确定是否遇到此问题

  1. 从数据库开始花费大量时间进行还原的那一时刻开始的错误日志。
  2. Management Studio 中,为所讨论的数据库执行 DBCC LOGINFO(DbName) 执行该操作时,数据库必须在线。注意:此查询执行时间依赖于 VLFs 文件的数量,因此可能花费较长时间 。在实际生产服务器上运行此操作时要小心。你可以使用类似于下面的脚本来标识每个日志文件的 VLFS 的数量。

注意:如果数据库包含数百万 VLFs,则此脚本会导致 temdb 的增长。

注意:不支持对数据库快照运行 DBCC LOGINFO

SET NOCOUNT ON 
GO 
CREATE TABLE #VLFs ( 
    FileId  INT NOT NULL, 
    FileSize BIGINT NOT NULL, 
    StartOffset BIGINT NOT NULL, 
    SeqNo INT NOT NULL, 
    Status INT NOT NULL, 
    Parity INT NOT NULL, 
    CreateLSN DECIMAL (25,0)) 
GO 
INSERT #VLFs EXEC ('DBCC LOGINFO (dbname) WITH NO_INFOMSGS') 
GO 
SELECT FileId , COUNT(*) AS VLF_Count FROM #VLFs GROUP BY FileId 
GO 
DROP TABLE #VLFs 
GO

查看哪些信息

  1. 为确认是否遇到此问题,检查处于正在恢复状态中的数据库的错误日志。你将在该数据库的日志中看到以下消息:
2008-06-26 10:29:20.48 spid58      Starting up database 'pubs'.

一旦预恢复完成,你将看到以下消息,它暗示恢复过程实际上已开始读取事务。在这个例子中,你可以看到,在下面的消息出现之前,花费了将近 9 分钟的时间。

2008-06-26 10:38:23.25 spid58      Analysis of database 'pubs' (12) is 37% complete (approximately 0 seconds remain). This is an informational message only. No user action is required.
  1. DBCCLOGINFO(DbName) 由于你将无法在数据库恢复期间收集这些信息,所以在恢复完成后立即运行上面的脚本,以便了解每个日志文件有多少个VLFS。对于我最近遇到的一个数据库,日志文件有 190 万个VLFS。(提示:DBCC 命令返回的行数与VLFS的数量相关)。文件大小列表示每个VLF的大小(以字节为单位)。以下是 DBCCLOG INFO 的示例输出:

image

解决方案

已经进行了几次修复以改善VLF问题中数据库的恢复时间。应用在以下的 KB 文章中的所有适用的修补程序:

当事务日志拥有大量虚拟日志文件时, 数据库的某些操作需要花费较长时间去完成或报错。请参考 2028436

作为替代解决方案,使用以下步骤减少VLs的数量:

  1. 运行 DBCC SHRINKFILE,将 ldf 文件 减少到较小的大小,从而减少VLFs的数量。

注意:不支持对数据库快照运行 DBCC LOGINFO

  1. 运行DBCC LOGINFO(DbName)或上面的脚本,并确保VLFs的数量小于 500-1000 。

  2. 使用单增长操作将日志文件展开(调整大小)到所需的大小。这可以通过在Database Properties->Files->Database files section中为LDF设置一个新的初始大小来实现。

  3. 运行DBCC LOGINFO(DbName)或上面的脚本,并确保VLFs的数量足够少。

注意:步骤 3 可以创建多个VLFs,即使你指定了一个较大的大小。然而,每个VLF都会很大。

  1. 关闭数据库的自动关闭选项。该选项可能会在每次启动数据库时产生不良影响。

  2. 备份数据库。

若事务日志中含有大量VLFs,则也会对数据库镜像产生影响。在 SQL Server 2005 实例上,若数据库事务日志中含有大量虚拟日志文件,则无法恢复主体数据库。

参考资料

How a log file structure can affect database recovery time

posted @   甲兵匪已  阅读(206)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示