数据库日志文件结构对数据库还原时间的影响
情景描述
我们经常遇到数据库需要很长时间才能恢复的情况。一个常见的场景是,在 SQL Server 重新启动之后,恢复过程必须前滚或回滚数据库的多个事务。然而,你可能还会看到以下症状之一,这些症状可能导致数据库需要很长时间才能恢复(即使日志文件中没有很多事务)。
- 从重新启动 SQL Server 或备份或还原或附加/分离或自动关闭这些状态启动数据库。
- 在事务复制中使用数据库时,日志读取进程延迟:日志读取进程的读取器线程负责扫描事务日志,以确定需要复制哪些事务。
原因
如果日志文件增长了几次(通常是由于非常小的自动增长设置),就会发生这种情况。结果,日志将有数千到几百万的 VLFs
你可以在 事务日志物理体系结构 中阅读更多关于 VLFs
的信息)。恢复数据库的第一阶段称为发现,在实际恢复开始之前,所有 VLFs
都被扫描(以串行和单线程方式)。由于这种情况发生在分析阶段之前,因此没有消息指示 SQL Server
错误日志中的进度。根据 VLFs
的数量,这个初始发现阶段可能需要几个小时,即使日志中没有需要处理的事务。
收集以下信息以确定是否遇到此问题
- 从数据库开始花费大量时间进行还原的那一时刻开始的错误日志。
- 在
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
查看哪些信息
- 为确认是否遇到此问题,检查处于正在恢复状态中的数据库的错误日志。你将在该数据库的日志中看到以下消息:
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.
DBCCLOGINFO(DbName)
由于你将无法在数据库恢复期间收集这些信息,所以在恢复完成后立即运行上面的脚本,以便了解每个日志文件有多少个VLFS
。对于我最近遇到的一个数据库,日志文件有 190 万个VLFS。(提示:DBCC 命令返回的行数与VLFS
的数量相关)。文件大小列表示每个VLF
的大小(以字节为单位)。以下是 DBCCLOG INFO 的示例输出:
解决方案
已经进行了几次修复以改善VLF
问题中数据库的恢复时间。应用在以下的 KB 文章中的所有适用的修补程序:
当事务日志拥有大量虚拟日志文件时, 数据库的某些操作需要花费较长时间去完成或报错。请参考 2028436
作为替代解决方案,使用以下步骤减少VLs
的数量:
- 运行
DBCC SHRINKFILE
,将ldf
文件 减少到较小的大小,从而减少VLFs
的数量。
注意:不支持对数据库快照运行
DBCC LOGINFO
。
-
运行
DBCC LOGINFO(DbName)
或上面的脚本,并确保VLFs
的数量小于 500-1000 。 -
使用单增长操作将日志文件展开(调整大小)到所需的大小。这可以通过
在Database Properties->Files->Database files section
中为LDF
设置一个新的初始大小来实现。 -
运行
DBCC LOGINFO(DbName)
或上面的脚本,并确保VLFs
的数量足够少。
注意:步骤 3 可以创建多个
VLFs
,即使你指定了一个较大的大小。然而,每个VLF
都会很大。
-
关闭数据库的自动关闭选项。该选项可能会在每次启动数据库时产生不良影响。
-
备份数据库。
若事务日志中含有大量VLFs
,则也会对数据库镜像产生影响。在 SQL Server 2005 实例上,若数据库事务日志中含有大量虚拟日志文件,则无法恢复主体数据库。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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框架的用法!