3. SQL Server恢复模型与日志架构
恢复模型决定了SQL Server如何记录事务日志、日志能否被截断、以及数据库在故障后能恢复到什么时间点。理解恢复模型与日志架构,是判断“日志为什么涨、能不能收缩、故障后能恢复到哪一秒”的基础。本节围绕三种恢复模型、事务日志的物理结构(VLF)、检查点机制以及崩溃恢复过程展开。
三种恢复模型的核心差异
恢复模型本质上是“日志记录粒度”与“日志截断时机”的组合选择,它直接决定了可恢复性和日志空间压力。
| 恢复模型 | 日志记录方式 | 日志截断时机 | 可恢复粒度 | 典型场景 |
|---|---|---|---|---|
| 简单(SIMPLE) | 最小化记录(部分操作) | 检查点后自动截断 | 仅到最近一次完整备份 | 开发库、只读报表库、可重建数据 |
| 完整(FULL) | 所有操作完整记录 | 日志备份后截断 | 可恢复到任意时间点(含日志备份链) | 生产核心库、金融、订单系统 |
| 大容量日志(BULK_LOGGED) | 大容量操作最小化记录,其余完整记录 | 日志备份后截断 | 可恢复到任意时间点,但大容量操作区间内无法精确到点 | 批量导入、索引重建窗口期 |
关键点:简单恢复模型下日志仍会增长,只是检查点后会自动截断可重用空间;如果长事务或复制/镜像等阻塞截断,日志依然会撑满。完整恢复模型下,不做日志备份,日志就永远不会被截断,这是生产库日志暴涨最常见的原因。
事务日志的物理结构:VLF
事务日志在物理上是一个或多个日志文件(.ldf),逻辑上被划分为多个虚拟日志文件(VLF,Virtual Log File)。SQL Server不直接管理字节,而是以VLF为单位进行分配、截断和重用。VLF的数量和大小由日志文件的增长方式决定:
- 日志文件初始创建时,按固定规则切分出若干VLF;
- 每次自动增长(如按10%或固定MB),会追加一段新空间并再次切分;
- 增长次数越多、每次增量越小,VLF数量越多、碎片越严重;
- VLF过多会导致日志备份、恢复、截断变慢,甚至影响启动速度。
可以用未公开但稳定的系统函数查看VLF分布:
DBCC LOGINFO('YourDatabase');
-- 每行一个VLF,关注 FileSize、StartOffset、FSeqNo、Status
-- Status = 2 表示该VLF是活动日志(active),不能被截断
-- Status = 0 表示可重用
判断标准:如果DBCC LOGINFO返回几百上千行,且大量VLF很小(如256KB),说明日志碎片严重。此时应通过一次“收缩+按合理大小重新增长”来重建VLF布局,而不是反复小步增长。
检查点与日志截断的关系
检查点(CHECKPOINT)是把内存中已修改的数据页(脏页)刷写到数据文件,并在日志中记录一个已知的、所有脏页都已落盘的起点。它的作用不是“清空日志”,而是推进可截断的日志边界。
- 简单恢复模型:检查点后,日志中早于“最小恢复LSN”的部分可被截断并重用;
- 完整/大容量日志恢复模型:检查点只推进可截断边界,真正截断要等日志备份完成;
- 长事务、未提交事务、复制、数据库镜像、AlwaysOn可用性组都会阻止日志截断。
因此,看到日志不收缩时,先查log_reuse_wait_desc:
SELECT name, log_reuse_wait_desc
FROM sys.databases
WHERE name = 'YourDatabase';
-- 常见值:NOTHING(可截断)、LOG_BACKUP(等日志备份)、
-- ACTIVE_TRANSACTION(长事务)、REPLICATION、AVAILABILITY_REPLICA 等
崩溃恢复过程
当SQL Server异常重启或数据库从意外状态恢复时,会经历三个阶段,这也是日志存在的根本意义:
- 分析阶段(Analysis):读取日志,确定哪些事务已提交、哪些未完成,构建脏页表和活动事务表。
- 重做阶段(Redo):把所有已提交但可能未写入数据文件的操作重新应用,保证已提交事务不丢失(Durability)。
- 撤销阶段(Undo):回滚未提交的事务,保证未提交数据不残留(Atomicity)。
恢复时间取决于需要重做/撤销的日志量。频繁的大事务、长时间未做检查点、日志文件过大,都会拉长恢复时间。生产库应控制单事务规模,并合理设置recovery interval(或间接检查点)以平衡恢复时间与运行时开销。
生产实践中的判断与处置
结合上述结构,遇到日志相关故障时可按以下顺序判断:
- 查
sys.databases.log_reuse_wait_desc,确认日志为何不能截断; - 若为
LOG_BACKUP,说明是完整/大容量日志模型且缺少日志备份,应补日志备份而非直接收缩; - 若为
ACTIVE_TRANSACTION,定位长事务并评估是否可提交或回滚; - 用
DBCC LOGINFO检查VLF数量,若碎片严重,在业务低峰做一次日志收缩并按合理增量重建; - 评估恢复模型是否匹配业务RPO:核心库必须完整恢复模型并建立日志备份链,批量窗口可临时切大容量日志以减少日志量,但完成后应切回完整并做日志备份。
理解恢复模型、VLF、检查点与崩溃恢复之间的因果链,才能在日志暴涨、恢复缓慢、无法恢复到指定时间点等故障中快速定位根因,而不是盲目收缩或重启。