SQL Server 2008 日志文件(.ldf)高达 59GB 怎么破?一次真实的排障与避坑记录
背景介绍
最近,生产环境的磁盘突然告警。登录服务器一查,发现考勤系统数据库 zktime 的日志文件(zktime_log.ldf)竟然高达 59,035 MB(近 59GB)!
由于是生产环境,第一反应是能不能直接把这个 .ldf 文件删了?
结论:绝对不能! 直接删除日志文件会导致数据库进入“可疑”状态,甚至数据丢失。
一、排查:为什么日志会这么大?
通过以下 SQL 语句查询数据库的状态:
SELECT
name AS [数据库名],
recovery_model_desc AS [恢复模式],
log_reuse_wait_desc AS [日志无法截断的原因]
FROM sys.databases
WHERE name = 'zktime';
查询结果:
- 恢复模式:
FULL(完整恢复模式) - 日志无法截断的原因:
LOG_BACKUP
分析:
在完整恢复模式下,SQL Server 需要记录所有的事务日志以支持时间点恢复。如果不定期进行“事务日志备份”,SQL Server 就认为日志里的数据还没存好,绝对不会释放空间。 这也就是为什么日志文件会无限膨胀。
二、踩坑:那些失败的收缩尝试
既然知道不能直接删,那就尝试收缩吧。
尝试 1:直接收缩
DBCC SHRINKFILE (N'zktime_log', 512);
结果: 报错 无法收缩日志文件 2 (zktime_log),因为该文件结尾的逻辑日志文件正在使用。
原因: 在完整模式下,只要没做日志备份,日志尾部就被死锁,无法从物理上截断。
尝试 2:做了日志备份后,再收缩
-- 1. 执行日志备份
BACKUP LOG [zktime] TO DISK = N'D:\sqlback\zktime_Log.trn' WITH INIT, COMPRESSION;
-- 2. 再次收缩
DBCC SHRINKFILE (N'zktime_log', 0, TRUNCATEONLY);
结果: 还是报同样的错。
原因: 虽然日志备份成功了(当时只备份出了 954KB 的真实变化量),但由于操作顺序或参数细节问题,导致依然卡在“正在使用”上。
三、破局:最终成功的一套组合拳
结合业务实际情况:我们的数据每天有全量备份,且部分数据会自动上传到其他地方,即使丢失一天的数据也能接受。
因此,决定将数据库改为“简单恢复模式(SIMPLE)”一劳永逸。
以下是最终成功的完美操作步骤:
第一步:先做一次日志备份(解锁尾部死结)
这一步至关重要,必须让状态从 LOG_BACKUP 变成 NOTHING。
USE [master];
GO
BACKUP LOG [zktime]
TO DISK = N'D:\sqlback\zktime_Log_Clear.trn'
WITH INIT, COMPRESSION;
GO
第二步:将恢复模式改为“简单”
简单模式下,SQL Server 会自动循环复用日志空间。
USE [master];
GO
ALTER DATABASE [zktime] SET RECOVERY SIMPLE;
GO
第三步:使用 TRUNCATEONLY 强制收缩
这一步是砍掉物理文件尾巴的关键!
USE [zktime];
GO
CHECKPOINT; -- 强制将内存脏页刷盘
GO
DBCC SHRINKFILE (N'zktime_log', 0, TRUNCATEONLY); -- 0 表示收缩到最小,TRUNCATEONLY 表示直接砍掉尾部空闲空间
GO
第四步:验证成果
USE [zktime];
GO
SELECT name AS [逻辑文件名], size * 8 / 1024 AS [当前大小(MB)]
FROM sys.database_files
WHERE type_desc = 'LOG';
GO
奇迹出现了: 那个 59035 MB 的文件,瞬间缩成了几百 MB。
四、事后总结与避坑指南
- 认清“恢复模式”:
- 如果你需要恢复到任意时间点(如金融、核心交易系统),请用 FULL(完整模式),但必须配合定期的日志备份(如每 30 分钟一次)。
- 如果你每天做一次全备,且能接受丢失当天的数据,直接改成 SIMPLE(简单模式),省时省力,日志永不膨胀。
- 关于
TRUNCATEONLY:直接写DBCC SHRINKFILE(文件, 512)是常规收缩(会移动内部页);而DBCC SHRINKFILE(文件, 0, TRUNCATEONLY)是直接释放文件尾部空间,速度更快且不会导致内部索引碎片化。 - 注意 SQL Server 版本:在 SQL Server 2008 中,
BACKUP LOG ... WITH TRUNCATE_ONLY语法已被废弃,请勿使用旧教程里的这种写法。 - 避免“自动收缩”:不要在数据库属性里勾选“自动收缩”,频繁收缩会产生大量磁盘碎片,严重影响数据库性能。
希望这篇记录能帮到遇到同样报错的兄弟们,少走弯路!

Thomas3 年前
发表在:SQL Server2008报错:值不能为空[S35]
Thomas3 年前
发表在:解决Composer Installing dependencies from lock file你这都看不清了
1112021-03-15 23:30
发表在:Cetnos7 新手安装ZABBIX4.0.5详解教程有人嘛
耗子2020-04-08 15:02
发表在:写给正在创业的自己看到了,想写点。可能我开过这网站了,以后...
Thomas2019-11-19 19:57
发表在:twcms您的IP地址已改变,为了安全考虑,请重新登录这个好
酷喵2016-08-03 15:22
发表在:我家侄女成长记前排支持啦!
五爷2015-12-01 03:26
发表在:关于centos中的相关查看命令@admin:呵呵
admin2015-12-01 01:49
发表在:关于centos中的相关查看命令非常不错