本文是在阅读《SQL Server Transaction Log Management》的Chapter 2: Log Internals时发现以往对Log Grows的理解比较片面,大部分内容引自原文,记录此文仅用于加深理解。
在讨论日志截断和空间重用时,我们会看到类似下面的结构图
A transaction log with 8 VLFs, after truncation
由于checkpoint(或者日志备份),VLF1和VLF2被截断并处于非活动状态。现在逻辑日志的开始位置是VLF3。VLF8因为还未被使用,所以仍然处于非活动状态。
当活动日志到达VLF7的尾部时会发生什么?
最简单的情形,一旦日志的逻辑结尾到达一个VLF的尾部,SQLServer将会开始重用下一个非活动的VLF。在上图中,将会是VLF8。当VLF8被写满之后,将会环绕到VLF1和VLF2并且重用它们。
如果没有可用的VLF可以被重用,那么日志需要自动增长,并分配更多的VLF。如果由于自动增长被禁用或者物理磁盘空间被占满,那么活动日志的逻辑尾部将会是日志文件的物理尾部。此时事务日志就会被写满,触发9002错误。
How SQL Server Grows the LOG
一直以为SQLServer先重用非活动的VLF,然后再启用自动增长。实际并非如此!!!
首先创建测试数据库及数据表
/********** SQL Server Transaction Log Management->Chapter2 **********/ --Listing 2.1: Re-creating the TestDB database, plus PrimaryTable_Large USE master ; IF DB_ID('TestDB') IS NOT NULL DROP DATABASE TestDB ; CREATE DATABASE TestDB ON PRIMARY ( NAME = N'TestDB' , FILENAME = N'D:\SQLData\TestDB.mdf' , SIZE = 199680KB , FILEGROWTH = 16384KB ) LOG ON ( NAME = N'TestDB_log' , FILENAME = N'D:\SQLData\TestDB_log.ldf' , SIZE = 2048KB , FILEGROWTH = 16384KB ); GO USE TestDB Go IF OBJECT_ID('dbo.PrimaryTable_Large', 'U') IS NOT NULL DROP TABLE dbo.PrimaryTable_Large GO CREATE TABLE PrimaryTable_Large ( ID INT IDENTITY PRIMARY KEY , SomeColumn CHAR(4) NULL , Filler CHAR(1500) DEFAULT '' ); GO ALTER DATABASE TestDB SET RECOVERY FULL; /*Initial full database backup of TestDB*/ BACKUP DATABASE TestDB TO DISK ='D:\SQLBackups\TestDB.bak' WITH INIT; GO DBCC SQLPERF(LOGSPACE) ; /*Log Size (MB): 2, Log Space used (%): 18*/ --检查恢复模式 SELECT NAME,recovery_model_desc FROM sys.databases WHERE NAME='TestDB' --last_log_backup_lsn为空则处于自动截断模式 SELECT DB_NAME(database_id) AS DatabaseName,last_log_backup_lsn FROM master.sys.database_recovery_status WHERE database_id=DB_ID('TestDB')