如果系统在下一个检查点之前出现故障,脏页会发生什么?

SEa*_*986 9 sql-server checkpoint

假设一个数据库使用完全恢复模式,当一条记录写入SQL Server(通过INSERT/ UPDATEetc)时,预写日志将确保在修改数据页之前将更改写入日志文件。

日志和数据页条目都在 RAM 中创建,稍后通过检查点提交到磁盘。

如果系统崩溃(为了论证而断电),脏页(在 RAM 中更改但未提交到磁盘的 IE 数据)会发生什么,因为 RAM 的内容无法在系统重新启动后幸存下来,这些数据是否丢失?

编辑

经过一些测试,我可以看到脏页没有丢失,但我不确定为什么:

使用本教程

创建一个测试数据库

CREATE DATABASE DirtyPagesDB
GO
USE DirtyPagesDB
GO
Run Code Online (Sandbox Code Playgroud)

关闭自动检查点

DBCC TRACEON(3505, -1);
DBCC TRACESTATUS();
Run Code Online (Sandbox Code Playgroud)

创建一个表,插入一些数据并发出一个检查点:

CREATE TABLE t1 (Speaker_Bio CHAR(8000))
GO
INSERT INTO t1 VALUES ('SQL'),('Authority')
GO
CHECKPOINT
Run Code Online (Sandbox Code Playgroud)

确认没有脏页

-- Get the rows of dirtied pages
SELECT
database_name = d.name,
OBJECT_NAME =
CASE au.TYPE
WHEN 1 THEN o1.name
WHEN 2 THEN o2.name
WHEN 3 THEN o1.name
END,
OBJECT_ID =
CASE au.TYPE
WHEN 1 THEN p1.OBJECT_ID
WHEN 2 THEN p2.OBJECT_ID
WHEN 3 THEN p1.OBJECT_ID
END,
index_id =
CASE au.TYPE
WHEN 1 THEN p1.index_id
WHEN 2 THEN p2.index_id
WHEN 3 THEN p1.index_id
END,
bd.FILE_ID,
bd.page_id,
bd.page_type,
bd.page_level
FROM sys.dm_os_buffer_descriptors bd
INNER JOIN sys.databases d
ON bd.database_id = d.database_id
INNER JOIN sys.allocation_units au
ON bd.allocation_unit_id = au.allocation_unit_id
LEFT JOIN sys.partitions p1
ON au.container_id = p1.hobt_id
LEFT JOIN sys.partitions p2
ON au.container_id = p2.partition_id
LEFT JOIN sys.objects o1
ON p1.OBJECT_ID = o1.OBJECT_ID
LEFT JOIN sys.objects o2
ON p2.OBJECT_ID = o2.OBJECT_ID
WHERE is_modified = 1
AND d.name = 'DirtyPagesDB'
AND
(
o1.name = 't1'
OR o2.name = 't1'
);
GO
Run Code Online (Sandbox Code Playgroud)

确认最后一个检查点的时间

SELECT  f1.[Checkpoint Begin], f2.[Checkpoint End]
FROM    fn_dblog(NULL, NULL) f1
        JOIN fn_dblog(NULL, NULL) f2
             On f1.[Current LSN] = f2.[Previous LSN]
WHERE   f2.Operation IN (N'LOP_BEGIN_CKPT', N'LOP_END_CKPT');
Run Code Online (Sandbox Code Playgroud)

添加更多行

INSERT INTO t1 VALUES ('SQL'),('Authority')
Run Code Online (Sandbox Code Playgroud)

使用上面的查询来确认有脏页

从任务管理器中杀死 SQL Server 任务以模拟断电。

启动服务

重新运行上面的命令以获取最后一个检查点时间,它是相同的(IE 没有运行检查点,除了我们手动执行的检查点)

从表 t1 中选择,所有四条记录都在那里

Dan*_*man 16

日志和数据页条目都在 RAM 中创建,稍后通过检查点提交到磁盘。

这种说法并不完全正确。Checkpoint(和 Lazy Writer)将数据页写入磁盘是正确的。但是,在提交事务时,日志记录会物理写入磁盘以保证事务的持久性。提交的事务数据永远不会只驻留在内存中(除非延迟持久性)。

所有数据修改首先写入日志(预写日志),然后写入脏页。页面和日志记录可能包括磁盘上已提交和未提交的数据。

无论采用何种恢复模式,SQL Server 在崩溃恢复期间都会将日志扫描到最后一个检查点,从该点前滚所有数据修改,最后回滚未提交的事务。