插入 0 次写入?

bmm*_*m6o 5 sql-server-2008

我最近一直在查看一些 SQL Profiler 跟踪记录,我看到了一些我不明白的东西。我正在运行简单的 INSERT 命令:

INSERT INTO Foo (ForeignID, FileExtension, MimeType) VALUES (1, 'FOO', 'Application/Foo')
Run Code Online (Sandbox Code Playgroud)

SQL Profiler 始终显示 0 次写入和 2 次读取。INSERT 上怎么可能没有任何写入?还是我误解了分析器在说什么?

为了完整起见,这是我正在使用的表定义:

CREATE TABLE [Foo](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ForeignID] [int] NOT NULL,
[FileExtension] [nvarchar](32) NOT NULL,
[MimeType] [nvarchar](96) NOT NULL,
CONSTRAINT [PK_ID] PRIMARY KEY CLUSTERED 
(
[ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 6

Profiler写入列记录为

服务器代表事件执行的物理磁盘写入次数。

在提交事务之前,必须将日志物理写入磁盘,但这些写入不会包含在 Profiler 报告的写入统计中。

对于许多插入,在语句完成之前可能不会发生物理写入,因为页面在缓冲区缓存中被修改并且直到稍后才写出到磁盘(例如通过检查点或惰性写入器进程)。

对于批量插入,有一个急切的写入器,因此页面可能会在之前写出到磁盘。有关更多信息,请参阅在 BOL 中编写页面

然而,以上似乎并不相关,因为即使没有页面写入磁盘,物理写入也可以报告为非零。

在下面的测试中,Profiler 报告了 5 次插入写入,但使用进程监视器监视文件写入并sys.dm_io_virtual_file_stats显示实际上没有发生。从中我得出结论,物理写入列实际上显示了变脏的页面数(理由是这些页面稍后需要写出到磁盘)

因此,基于该假设,SQL Profiler 在您的测试中显示 0 Writes,因为您正在插入一个已经脏的页面。

TRUNCATE TABLE Foo

CHECKPOINT;

DBCC DROPCLEANBUFFERS;

/*Returns 0 rows*/
SELECT *
FROM   sys.dm_os_buffer_descriptors
WHERE  database_id = DB_ID()
       AND is_modified = 1

SELECT 'Before Insert', num_of_writes, num_of_bytes_written
FROM   sys.dm_io_virtual_file_stats(db_id(), 1)

INSERT INTO Foo
            (ForeignID,
             FileExtension,
             MimeType)
VALUES      ( 1,
              'FOO',
              'Application/Foo')

/*Nothing Written. Figures same as previous query*/
SELECT 'After Insert', num_of_writes, num_of_bytes_written
FROM   sys.dm_io_virtual_file_stats(db_id(), 1)

/*Returns 5 rows*/
SELECT *
FROM   sys.dm_os_buffer_descriptors
WHERE  database_id = DB_ID()
       AND is_modified = 1

CHECKPOINT;

/*Shows physical writes*/
SELECT 'After Checkpoint', num_of_writes, num_of_bytes_written
FROM   sys.dm_io_virtual_file_stats(db_id(), 1) 
Run Code Online (Sandbox Code Playgroud)

探查器跟踪

探查器

进程监视器写入后 CHECKPOINT

程序门

所以 CheckPoint 实际上实际写了 8 个页面(6 个单页和 1 个双页),但在 Profiler 中显示为只负责 4 个。

从进程监视器屏幕截图中的偏移量,可以准确地看到哪些页面被写入

+-----+---------------+-----------+
|  57 | syscolpars    | DATA_PAGE |
|  86 | sysrscols     | DATA_PAGE |
|  93 | sysrowsets    | DATA_PAGE |
| 143 | sysallocunits | DATA_PAGE |
| 168 | Foo           | DATA_PAGE |
| 169 | Foo           | IAM_PAGE  |
|   1 |               | PFS_PAGE  |
|   9 |               | BOOT_PAGE |
+-----+---------------+-----------+
Run Code Online (Sandbox Code Playgroud)

输出中未显示的另外三个页面dm_os_buffer_descriptors是数据库引导页面和sysrscols, sysrowsets

CHECKPOINT随着dbi_checkptLSN字段的更新,数据库引导页的写入与自身相关。

预计插入会导致其他两个页面被更新(分别为Thercmodifiedrcrows列),但这似乎不会立即发生,而且我LOP_COUNT_DELTA在日志文件中也看不到任何 条目,所以我认为这必须定期发生,而不是在之后发生每一次修改。

我不确定如何解释被报告的 9 次写入,但只发生了 8 次。也许一页被重复计算了。

  • 很好的测试,很好的答案。与现实生活中的值相比,似乎 Write 列文档可能有所简化。 (2认同)