SQL Server 模拟checksum检测错误

要模拟备份时 CHECKSUM 检测到错误并中断,最有效的方法是直接修改数据库数据页的底层二进制数据(即人为制造物理损坏/Page Corruption)。

在 SQL Server 中,无法通过常规的 UPDATE 语句破坏页面校验和,因为引擎会自动重新计算。我们需要使用未公开的危险命令 DBCC WRITEPAGE 来直接篡改磁盘上的字节。

以下是完整的模拟步骤(请务必在独立的测试数据库中操作,绝对不能在生产环境运行!):


第一步:准备测试数据库和表

首先,创建一个名为 TestVerify 的干净数据库,并写入一条测试数据。

复制代码
-- 1. 创建测试数据库
CREATE DATABASE TestVerify;
GO

USE TestVerify;
GO

-- 2. 设置页面校验和为 CHECKSUM(默认通常也是这个)
ALTER DATABASE TestVerify SET PAGE_VERIFY CHECKSUM;
GO

-- 3. 创建一张简单的表并插入数据
CREATE TABLE TestTable (ID INT IDENTITY(1,1), Name VARCHAR(100));
INSERT INTO TestTable (Name) VALUES ('Row_To_Be_Corrupted');
GO

第二步:找出数据所在的物理页面(Page ID)

我们需要知道数据存放在哪个数据页上,以便对其进行精准破坏。

复制代码
-- 使用 DBCC IND 查看表的页面分配
-- 参数: ('数据库名', '表名', 1代表聚集索引或堆)
DBCC IND ('TestVerify', 'TestTable', 1);
GO

运行后在结果集中找到:

  • PageType = 1 的那一行(1 代表数据页 Data Page)。
  • 记住这一行的 PageFID(文件 ID,通常是 1)和 PagePID(页面 ID,例如是 240)。

直接篡改数据行的内容(比如把字母 'R' 改掉)

复制代码
-- 1. 开启跟踪标记,允许将 DBCC 的结果输出到 SSMS 消息窗口
DBCC TRACEON (3604);
GO

-- 2. 查看页面内容
-- 参数: ('数据库名', 文件ID, 页面ID, 输出格式)
-- 输出格式 0 代表只打印页面头部,1 代表打印每行的十六进制和文本对照(推荐)
DBCC PAGE ('TestVerify', 1, 240, 1);
GO
  • 原值分析 :在数据行的内存镜像中,十六进制的 52 代表大写字母 R (即 Row 的开头)。
  • 寻找绝对偏移量(Offset)
    1. Slot 0 的起始绝对偏移量是 0x60 (十进制的 96)。
    2. 3000... 开始数,十六进制的 52 位于第 16 个字节的位置(从 0 开始算偏移是 15)。
    3. 因此,字母 'R' 在整个页面中的绝对偏移量是 96 + 15 = 111

你想改成 0x33 的话,命令应该这样写:


第三步:使用 DBCC WRITEPAGE 故意破坏页面结构

现在,我们把数据库设为单用户模式,然后直接向这个页面写入错误的垃圾数据,从而破坏它的 Checksum 校验。

注意:请将下面代码中的 312 替换为你上一步实际查到的 PagePID

复制代码
-- 切换单用户模式
ALTER DATABASE TestVerify SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
DBCC TRACEON (3604, 2588);
GO

-- 将偏移量设为 111,把字母 'R' (0x52) 强行篡改为 0x33(字符 '3')
DBCC WRITEPAGE ('TestVerify', 1, 240, 111, 1, 0x33,1);
GO

DBCC TRACEOFF (3604, 2588);
GO
-- 恢复多用户
ALTER DATABASE TestVerify SET MULTI_USER;
GO

-- 1. 开启跟踪标记,允许将 DBCC 的结果输出到 SSMS 消息窗口
DBCC TRACEON (3604);
GO

-- 2. 查看页面内容
-- 参数: ('数据库名', 文件ID, 页面ID, 输出格式)
-- 输出格式 0 代表只打印页面头部,1 代表打印每行的十六进制和文本对照(推荐)
DBCC PAGE ('TestVerify', 1, 240, 1);
GO


第四步:测试备份,见证 CHECKSUM 报错 🚨

现在,我们运行带有 WITH CHECKSUM 的备份命令。由于磁盘上的页面已被破坏,备份会立刻中断并报出物理损坏的错误。

复制代码
BACKUP DATABASE [TestVerify] TO  DISK = N'S:\tmp\TestVerify.bak' WITH NOFORMAT, INIT,  
NAME = N'TestVerify-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = 10, CHECKSUM
GO

Expected Output (预期错误信息):

你会看到类似下面的报错,提示遇到了 输入/输出(I/O)错误,并且明确指出了 Checksum 不匹配

通过这个实验,你可以直观地看到 CHECKSUM 是如何在第一时间内拦截坏数据的。如果你想进一步了解当遇到这种备份报错时,应该通过什么步骤去尝试挽救或修复数据库,请告诉我!

相关推荐
数智启示录5 天前
Flink CDC 机制精讲(四):一条 SQLServer CDC 事件如何保持顺序 【面试宝典】
数据库·面试·sqlserver·flink
数据库小学妹7 天前
SQL Server数据迁移怎么做?一次事故复盘:备份还原、bcp、CDC、KDTS全拆解
sqlserver·备份还原·数据库迁移·信创迁移·sqlserver数据迁移
xuefuhe7 天前
SQL Server exec vs sp_executesql
sqlserver
zengjuan10058 天前
[特殊字符]️ 松鼠备份 | 数据库备份方案即将重磅上线!三大模式组合拳,精准守护SQL Server每一笔数据
数据库·sqlserver·数据库备份·全量备份·增量备份·差异备份·日志和事务备份
识途老码8 天前
docker运行sqlserver
docker·容器·sqlserver
熊文豪17 天前
SQLServer数据迁移之后,那张报表还能不能秒出
数据库·sqlserver·电科金仓
Alex Gram18 天前
数据库同步工具PanguSync图文教程
java·mysql·postgresql·sqlserver·c#·数据库同步软件·数据库同步工具
哥本哈士奇20 天前
dbt+SQLServer构建数据仓库(10):macro 以及 data vault的应用实例
大数据·数据仓库·sqlserver
哥本哈士奇(aspnetx)21 天前
dbt+SQLServer构建数据仓库(10):macro 以及 data vault的应用实例
sqlserver