数据库日志文件结构对数据库还原时间的影响
我们经常遇到数据库需要很长时间才能恢复的情况。一个常见的场景是,在 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 实例上,若数据库事务日志中含有大量虚拟日志文件,则无法恢复主体数据库。

浙公网安备 33010602011771号