即时文件初始化是否适用于手动日志文件增长?

Bre*_*zar 7 sql-server transaction-log sql-server-2022

SQL Server 2022 引入了针对事务日志文件增长事件的即时文件初始化。在2022 年新增功能页面中,微软指出:

一般来说,事务日志文件无法从即时文件初始化 (IFI) 中受益。从 SQL Server 2022 (16.x)(所有版本)和 Azure SQL 数据库开始,即时文件初始化可以使事务日志增长事件受益最多 64 MB。新数据库的默认自动增长大小增量为 64 MB。大于 64 MB 的事务日志文件自动增长事件无法从即时文件初始化中受益。

为了测试这一点,我尝试反复以不同大小(例如 50 和 70MB)增长日志文件,但是......它们都不是瞬时的。

DROP DATABASE LogGrowthTest;
GO
CREATE DATABASE [LogGrowthTest]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'LogGrowthTest', FILENAME = N'Z:\MSSQL\Data\LogGrowthTest.mdf', 
    SIZE = 8192KB , FILEGROWTH = 60000KB )
 LOG ON 
( NAME = N'LogGrowthTest_log', FILENAME = N'Z:\MSSQL\Data\LogGrowthTest_log.ldf' , 
    SIZE = 8192KB , FILEGROWTH = 60000KB )
GO
DECLARE @TestStartTime DATETIME2 = GETDATE(), @i INT = 1,
    @StringStarter NVARCHAR(4000) = N'ALTER DATABASE [LogGrowthTest] MODIFY FILE ( NAME = N''LogGrowthTest_log'', SIZE = ',
    @StringToExec NVARCHAR(4000);   
WHILE @i < 101
    BEGIN
    /* CHANGE THE 63 IN THE BELOW LINE TO CHANGE FILE GROWTH SIZE: */
    SET @StringToExec = @StringStarter + CAST((@i * 63) AS NVARCHAR(10)) + N'MB );';
    PRINT(@StringToExec)
    EXEC(@StringToExec);
    SET @i = @i + 1;
    END
SELECT DATEDIFF(millisecond,@TestStartTime, GETDATE()) AS TestDurationSeconds
GO
Run Code Online (Sandbox Code Playgroud)

我尝试了 63MB、65MB,似乎没有太大区别 - 100 个增长事件的测试大约需要 15-16 秒。

所以问题是,即时文件初始化是否不适用于手动日志文件增长,即使是小尺寸?只有自动增长事件吗?(我还无法证明它也适用于自动增长事件。)

Mar*_*ith 8

即时文件初始化是否适用于手动日志文件增长?

是的,它确实。

我在 SQL Server 2019 和 SQL Server 2022 上尝试了以下操作(在安装过程中启用了 IFI)

CREATE DATABASE [LogGrowthTest]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'LogGrowthTest', FILENAME = N'...LogGrowthTest.mdf' , SIZE = 8MB , FILEGROWTH = 60000KB  )
 LOG ON 
( NAME = N'LogGrowthTest_log', FILENAME = N'...LogGrowthTest_log.ldf' , SIZE = 8MB , FILEGROWTH = 60000KB  )
GO

ALTER DATABASE [LogGrowthTest] MODIFY FILE ( NAME = N'LogGrowthTest_log', SIZE = 64MB );
Run Code Online (Sandbox Code Playgroud)

对于 SQL Server 2019,我可以看到整个新分配的文件部分以 8MB 块的形式写入(从长度和偏移量来看)

在此输入图像描述

ProcMon 中的堆栈显示此活动发生在文件清零过程中

在此输入图像描述

2022年无此对应栏目

在此输入图像描述

在 2019 年的情况下,第一个和最后一个 procmon 条目之间经过的时间为 46 毫秒(21:30:54.8866621 到 21:30:54.9330198),在 2022 年的情况下为 7.9 毫秒(21:31:54.8078691 到 21:31:54.8157769)。

我也通过输出看到了类似的时间差异SET STATISTICS TIME ON

两者都写入同一个笔记本电脑光盘(眼尖的人可能会注意到上面我不小心将我的 2022 实例命名为 20222)。

我很感兴趣为什么循环表现如此糟糕。看来只有第一个条目真正受益于 IFI。

当我将以下内容添加到上面的代码中时...

ALTER DATABASE [LogGrowthTest] MODIFY FILE ( NAME = N'LogGrowthTest_log', SIZE = 127MB );
Run Code Online (Sandbox Code Playgroud)

第二次增长花费的时间明显更长,并且写入文件的更多内容(包括之前未初始化的部分)

在此输入图像描述

这不是由于将文件清零所致,而且也不是我在 SQL Server 2019 实例中看到的情况,因此似乎是与此功能可能相关或无关的额外工作。

令人烦恼的是,出于某种原因,ProcMon 只是向我显示了一个空白选项卡,而不是突出显示的 WriteFile 的调用堆栈,但 Windows 性能记录器会暗示这是花费在sqlmin.dll!SQLServerLogMgr::FormatVirtualLogFile(这与 Paul 的答案相关)

在此输入图像描述


Pau*_*ite 8

使用以下方法在我的本地 2022 年实例上确认:

SET NOCOUNT ON;

DECLARE 
    @CurrentSize integer,
    @i integer = 1,
    @SQL nvarchar(max);

SELECT @CurrentSize = DF.size * 8 / 1024
FROM sys.database_files AS DF
WHERE DF.[name] = N'Sandpit_log';

WHILE @i <= 10
BEGIN
    SET @SQL = CONCAT
    (
        N'
        ALTER DATABASE Sandpit 
        MODIFY FILE 
        (
            NAME = N''Sandpit_log'', 
            SIZE = ',
            @CurrentSize + (@i * 64),
            N', 
            FILEGROWTH = 64MB
            );'
    )
    EXECUTE (@SQL);
    SET @i += 1;
END;
Run Code Online (Sandbox Code Playgroud)

全局跟踪标志 3004(显示即时文件初始化详细信息)和 1810(增长事件详细信息)的输出以及 3604 还启用了将输出直接输出到 SSMS 消息选项卡:

SET NOCOUNT ON;

DECLARE 
    @CurrentSize integer,
    @i integer = 1,
    @SQL nvarchar(max);

SELECT @CurrentSize = DF.size * 8 / 1024
FROM sys.database_files AS DF
WHERE DF.[name] = N'Sandpit_log';

WHILE @i <= 10
BEGIN
    SET @SQL = CONCAT
    (
        N'
        ALTER DATABASE Sandpit 
        MODIFY FILE 
        (
            NAME = N''Sandpit_log'', 
            SIZE = ',
            @CurrentSize + (@i * 64),
            N', 
            FILEGROWTH = 64MB
            );'
    )
    EXECUTE (@SQL);
    SET @i += 1;
END;
Run Code Online (Sandbox Code Playgroud)

%l64d跟踪标志 1810 在其格式字符串(而不是)中存在错误%I64d。如果您自己不解决这个问题,您可以使用扩展事件来监控database_file_size_change增长modify_file_operation。据我所知,没有任何事件可以监视 IFI,因此该部分需要 3004。


sys.dm_db_log_info在日志增长之前:

数据库ID 文件ID vlf_开始_偏移量 vlf_size_mb vlf_序列号 vlf_活动 vlf_状态 vlf_奇偶校验 vlf_first_lsn vlf_create_lsn vlf_加密器_指纹
5 2 8192 1.93 87 0 0 128 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 2039808 1.93 88 0 0 128 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 4071424 1.93 89 1 2 128 00000059:00000010:0001 00000000:00000000:0000 无效的
5 2 6103040 2.17 42 0 0 64 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 8388608 56 43 0 0 64 00000000:00000000:0000 00000027:0000010B:0001 无效的

然后:

数据库ID 文件ID vlf_开始_偏移量 vlf_size_mb vlf_序列号 vlf_活动 vlf_状态 vlf_奇偶校验 vlf_first_lsn vlf_create_lsn vlf_加密器_指纹
5 2 8192 1.93 87 0 0 128 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 2039808 1.93 88 0 0 128 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 4071424 1.93 89 1 2 128 00000059:00000010:0001 00000000:00000000:0000 无效的
5 2 6103040 2.17 42 0 0 64 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 8388608 56 43 0 0 64 00000000:00000000:0000 00000027:0000010B:0001 无效的
5 2 67108864 64 0 0 0 0 00000000:00000000:0000 00000059:0000088F:0002 无效的
5 2 134217728 64 0 0 0 0 00000000:00000000:0000 00000059:00000896:0001 无效的
5 2 201326592 64 0 0 0 0 00000000:00000000:0000 00000059:0000089D:0001 无效的
5 2 268435456 64 0 0 0 0 00000000:00000000:0000 00000059:000008A4:0001 无效的
5 2 335544320 64 0 0 0 0 00000000:00000000:0000 00000059:000008AB:0001 无效的
5 2 402653184 64 0 0 0 0 00000000:00000000:0000 00000059:000008B2:0001 无效的
5 2 469762048 64 0 0 0 0 00000000:00000000:0000 00000059:000008B9:0001 无效的
5 2 536870912 64 0 0 0 0 00000000:00000000:0000 00000059:000008C0:0001 无效的
5 2 603979776 64 0 0 0 0 00000000:00000000:0000 00000059:000008C7:0001 无效的
5 2 671088640 64 0 0 0 0 00000000:00000000:0000 00000059:000008CE:0001 无效的

注意到每个增长都添加了一个虚拟日志文件 (VLF)。


可以使用全局跟踪标志 1837禁用新功能。设置该标志后,输出将更改为:

Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 8192 to 16384 (Offset 0x4000000 to 0x8000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 131072 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 16384 to 24576 (Offset 0x8000000 to 0xc000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 196608 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 24576 to 32768 (Offset 0xc000000 to 0x10000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 262144 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 32768 to 40960 (Offset 0x10000000 to 0x14000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 327680 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 40960 to 49152 (Offset 0x14000000 to 0x18000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 393216 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 49152 to 57344 (Offset 0x18000000 to 0x1c000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 458752 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 57344 to 65536 (Offset 0x1c000000 to 0x20000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 524288 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 65536 to 73728 (Offset 0x20000000 to 0x24000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 589824 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 73728 to 81920 (Offset 0x24000000 to 0x28000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 655360 KB).
Skip zeroing D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf from page 81920 to 90112 (Offset 0x28000000 to 0x2c000000) 64 mb
Grow the file D:\Databases\MSSQL16.SQL2022\MSSQL\DATA\Sandpit_log.ldf (file_id = 2, auto_grow = 0, growth = 65536 KB, new_size = 720896 KB).
Run Code Online (Sandbox Code Playgroud)

重置到相同的起点并再次运行十增长脚本,日志DMV显示:

数据库ID 文件ID vlf_开始_偏移量 vlf_size_mb vlf_序列号 vlf_活动 vlf_状态 vlf_奇偶校验 vlf_first_lsn vlf_create_lsn vlf_加密器_指纹
5 2 8192 1.93 87 0 0 128 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 2039808 1.93 88 0 0 128 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 4071424 1.93 89 1 2 128 00000059:00000010:0001 00000000:00000000:0000 无效的
5 2 6103040 2.17 42 0 0 64 00000000:00000000:0000 00000000:00000000:0000 无效的
5 2 8388608 56 43 0 0 64 00000000:00000000:0000 00000027:0000010B:0001 无效的
5 2 67108864 16 0 0 0 0 00000000:00000000:0000 00000059:000008F6:0001 无效的
5 2 83886080 16 0 0 0 0 00000000:00000000:0000 00000059:000008F6:0001 无效的
5 2 100663296 16 0 0 0 0 00000000:00000000:0000 00000059:000008F6:0001 无效的
5 2 117440512 16 0 0 0 0 00000000:00000000:0000 00000059:000008F6:0001 无效的
5 2 134217728 16 0 0 0 0 00000000:00000000:0000 00000059:000008FE:0001 无效的
5 2 150994944 16 0 0 0 0 00000000:00000000:0000 00000059:000008FE:0001 无效的
5 2 167772160 16 0 0 0 0 00000000:00000000:0000 00000059:000008FE:0001 无效的
5 2 184549376 16 0 0 0 0 00000000:00000000:0000 00000059:000008FE:0001 无效的
5 2 201326592 16 0 0 0 0 00000000:00000000:0000 00000059:00000906:0001 无效的
5 2 218103808 16 0 0 0 0 00000000:00000000:0000 00000059:00000906:0001 无效的
5 2 234881024 16 0 0 0 0 00000000:00000000:0000 00000059:00000906:0001 无效的
5 2 251658240 16 0 0 0 0 00000000:00000000:0000 00000059:00000906:0001 无效的
5 2 268435456 16 0 0 0 0 00000000:00000000:0000 00000059:0000090E:0001 无效的
5 2 285212672 16 0 0 0 0 00000000:00000000:0000 00000059:0000090E:0001 无效的
5 2 301989888 16 0 0 0 0 00000000:00000000:0000 00000059:0000090E:0001 无效的
5 2 318767104 16 0 0 0 0 00000000:00000000:0000 00000059:0000090E:0001 无效的
5 2 335544320 16 0 0 0 0 00000000:00000000:0000 00000059:00000916:0001 无效的
5 2 352321536 16 0 0 0 0 00000000:00000000:0000 00000059:00000916:0001 无效的
5 2 369098752 16 0 0 0 0 00000000:00000000:0000 00000059:00000916:0001 无效的
5 2 385875968 16 0 0 0 0 00000000:00000000:0000 00000059:00000916:0001 无效的
5 2 402653184 16 0 0 0 0 00000000:00000000:0000 00000059:0000091E:0001 无效的
5 2 419430400 16 0 0 0 0 00000000:00000000:0000 00000059:0000091E:0001 无效的
5 2 436207616 16 0 0 0 0 00000000:00000000:0000 00000059:0000091E:0001 无效的
5 2 452984832 16 0 0 0 0 00000000:00000000:0000 00000059:0000091E:0001 无效的
5 2 469762048 16 0 0 0 0 00000000:00000000:0000 00000059:00000926:0001 无效的
5 2 486539264 16 0 0 0 0 00000000:00000000:0000 00000059:00000926:0001 无效的
5 2 503316480 16 0 0 0 0 00000000:00000000:0000 00000059:00000926:0001 无效的
5 2 520093696 16 0 0 0 0 00000000:00000000:0000 00000059:00000926:0001 无效的
5 2 536870912 16 0 0 0 0 00000000:00000000:0000 00000059:0000092E:0001 无效的
5 2 553648128 16 0 0 0 0 00000000:00000000:0000 00000059:0000092E:0001 无效的
5 2 570425344 16 0 0 0 0 00000000:00000000:0000 00000059:0000092E:0001 无效的
5 2 587202560 16 0 0 0 0 00000000:00000000:0000 00000059:0000092E:0001 无效的
5 2 603979776 64 0 0 0 0 00000000:00000000:0000 00000059:00000936:0001 无效的
5 2 671088640 64 0 0 0 0 00000000:00000000:0000 00000059:0000093D:0001 无效的

请注意,大多数 64MB 增长会导致 4 x 16MB VLF。