如果系统在下一个检查点之前发生故障,那么脏页会怎样?


8

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

日志和数据页条目均在RAM中进行,然后由Checkpoint提交到磁盘。

如果发生系统崩溃(出于参数争用而断电),脏页(在RAM中更改但未提交到磁盘的IE数据)会发生什么情况,因为RAM的内容在系统重新启动后无法生存,是否会丢失数据? ?

编辑

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

使用本教程

创建一个测试数据库

CREATE DATABASE DirtyPagesDB
GO
USE DirtyPagesDB
GO

关闭自动检查点

DBCC TRACEON(3505, -1);
DBCC TRACESTATUS();

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

CREATE TABLE t1 (Speaker_Bio CHAR(8000))
GO
INSERT INTO t1 VALUES ('SQL'),('Authority')
GO
CHECKPOINT

确认没有脏页

-- 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

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

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');

添加更多行

INSERT INTO t1 VALUES ('SQL'),('Authority')

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

从任务管理器中终止SQL Server任务以模拟关闭电源。

启动服务

重新运行上面的命令以获取最后一个检查点时间,这是相同的(即除我们手动执行的检查点外,没有其他检查点已运行)

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

Answers:


15

日志和数据页条目均在RAM中进行,然后由Checkpoint提交到磁盘。

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

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

不管恢复模型如何,SQL Server都会在崩溃恢复期间将日志扫描到最后一个检查点,将所有数据修改从该点向前滚动,最后回滚未提交的事务。


@ SEarle1986,很高兴这个答案有助于您的理解。我所引用的文档中埋藏着以下要点:[SQL Server具有防止在写入关联的日志记录之前刷新脏页的逻辑。提交事务后,日志记录将写入磁盘。”
丹·古兹曼

使用最少记录的操作,空间分配(对IAM,PFS和GAM结构的更改)将前滚,然后在未提交的情况下回滚,因此该操作为全无。通过批量插入对数据页所做的更改无需前滚,因为这些更改是在操作过程中物理写入的(这与正常记录的操作不同,在常规操作中,数据文件IO通过惰性写入器和检查点是异步的)。
丹·古兹曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.