事务日志暴增的根本原因是日志写入持续发生但空间无法回收;主因包括完整恢复模式下未做日志备份、存在长时间未提交事务、大事务集中执行及日志自动增长设置不合理。

事务日志暴增的根本原因不是“插得多”,而是“无法回收”
SQL Server 事务日志暴涨,从来不是因为 INSERT 太多,而是日志空间写进去了却一直不能被截断(truncate)。只要有一个条件不满足,哪怕只插 1 行,日志也可能卡住不释放。最常见、最隐蔽的罪魁祸首是:数据库处于 Full 恢复模式,但没做 LOG BACKUP。
完整恢复模式下,不做日志备份 = 日志永不清零
在 Full 模式中,SQL Server 不会自动清理已提交事务的日志记录——它必须等你执行 BACKUP LOG,才会把这部分日志标记为“可重用”。没备份,日志文件就只能靠自动增长硬撑。
- 用
DBCC SQLPERF(logspace)查看Log Space Used (%),超过 70% 就该警觉 - 查最近一次日志备份时间:
SELECT database_name, backup_finish_date FROM msdb.dbo.backupset WHERE type = 'L' ORDER BY backup_finish_date DESC - 如果结果为空或最后备份是几小时前,基本可以锁定问题
长时间未提交的事务会“钉住”整段日志
一个开着没 COMMIT 或 ROLLBACK 的事务,会让从它开始那一刻起的所有日志都不可截断。哪怕其他 999 个事务早已完成,这部分日志照样锁死。
- 典型场景:SSMS 里手动
BEGIN TRAN后关掉窗口、应用连接异常中断、游标读取慢导致事务挂起 - 快速定位:
DBCC OPENTRAN显示最早活动事务的SPID和开始时间 -
KILL <spid></spid>能立刻释放空间,但得先确认该事务是否还在业务关键路径上
BULK INSERT 或大事务本身不危险,危险的是没配对策略
BULK INSERT 本意是走最小日志路径,但默认行为其实是“全量日志”——只有同时满足三个条件才启用最小日志:
- 目标表无活跃非聚集索引(或建表时加
WITH (DATA_COMPRESSION = ...)等兼容选项) - 显式指定
WITH (TABLOCK),漏掉就退化成行锁 + 全量日志 - 数据库恢复模式是
BULK_LOGGED或SIMPLE(Full模式下无效)
别只改语句不改库:执行前必须 ALTER DATABASE yourdb SET RECOVERY BULK_LOGGED,导入完立刻切回 Full 并做一次 BACKUP LOG,否则后续日志永远无法截断。
真正容易被忽略的点:自动增长设置和 tempdb 压力是放大器
即使你解决了备份和事务问题,不当的 log file autogrowth 设置仍会让日志“一步错、步步胀”。比如设成每次增长 1MB,在百万行插入中可能触发上千次增长操作,每轮都要初始化新页、更新文件头、同步 IO,反而拖慢整体速度。
更隐蔽的是 tempdb:当批量插入触发排序、哈希或版本存储(如 RCSI 开启时),tempdb 会成为瓶颈。而它的争用往往表现为日志写入变慢、WRITELOG 等待飙升——你以为是日志问题,实际是 tempdb 文件不够或没均分到多个文件。

















