备份检测到损坏,但 CHECKDB 没有

Ele*_*ero 12 sql-server corruption dbcc-checkdb

我有一个数据库,当我运行备份命令时

BACKUP DATABASE [MyDatabase] TO     
DISK =  'G:\Backup\MyDatabase_01_01_2018.bak'   
WITH    NOFORMAT, NOSKIP, COMPRESSION, INIT, BUFFERCOUNT = 100
Run Code Online (Sandbox Code Playgroud)

我收到错误消息

消息 3043,级别 16,状态 1,第 8 行
BACKUP 'MyDatabase' 在文件 'F:\Data\MyDatabase_1.ndf' 中的页面 (1:745345) 上检测到错误。
消息 3013,级别 16,状态 1,第 8 行
BACKUP DATABASE 异常终止。

我运行了一个完整的 CHECKDB,但它回来了。我确实注意到页面验证选项已设置为 NONE(不是我做的),因此我将其更改为 CHECKSUM 并重建数据库中的所有索引以使其写入所有页面并生成校验和。在此之后备份仍然失败并且 checkdb 仍然显示干净(所以没有变化)。

DBCC CHECKDB('MyDatabase') WITH NO_INFOMSGS, ALL_ERRORMSGS,
DATA_PURITY, EXTENDED_LOGICAL_CHECKS;
Run Code Online (Sandbox Code Playgroud)

从 SQL 日志:

xxx 执行的 DBCC CHECKDB (MyDatabase) WITH all_errormsgs, no_infomsgs, data_purity 发现 0 个错误并修复了 0 个错误。已用时间:0 小时 21 分 46 秒。内部数据库快照具有分割点 LSN = 000ab776:0000112f:0001 和第一个 LSN = 000ab776:0000112d:0001。

我运行了 DBCC PAGE 但它出错了(甚至似乎没有首先返回正确的页面)。我可以使用打印选项 2 运行它并返回,但老实说我不知道​​我在那里寻找什么。

DBCC PAGE ('MyDatabase',1,745345,3)
Run Code Online (Sandbox Code Playgroud)
页: (3:513793)

缓冲:


BUF @0x00000003811F8280

bpage = 0x00000000F2D70000 bhash = 0x0000000000000000 bpageno = (1:745345)
bdbid = 5 breferences = 0 bcputicks = 0
bsampleCount = 0 bUse1 = 44283 bstat = 0x809
博客 = 0x5adb215a bnext = 0x0000000000000000          

页眉:


页@0x00000000F2D70000

m_pageId = (3:513793) m_headerVersion = 1 m_type = 2
m_typeFlagBits = 0x4 m_level = 0 m_flagBits = 0x0
m_objId (AllocUnitId.idObj) = 1075937538 m_indexId (AllocUnitId.idInd) = 2
元数据:AllocUnitId = 633462595911680 元数据:PartitionId = 0
元数据:IndexId = -1 元数据:ObjectId = 0 m_prevPage = (3:513795)
m_nextPage = (3:513820) pminlen = 17 m_slotCnt = 426
m_freeCnt = 2 m_freeData = 7338 m_reservedCnt = 0
m_lsn = (608841:643611:411) m_xactReserved = 0 m_xdesId = (0:0)
m_ghostRecCnt = 0 m_tornBits = 0 DB 片段 ID = 1

分配状态

GAM (1:511232) = 分配的 SGAM (1:511233) = 未分配     
PFS (1:744096) = 0x40 分配 0_PCT_FULL DIFF (1:511238) = 未更改
ML (1:511239) = NOT MIN_LOGGED      

消息 2514,级别 16,状态 8,第 20 行
发生 DBCC PAGE 错误:页面元数据无效 - 转储样式 3 不可能。

任何想法我接下来可以尝试什么?服务器版本是

select @@version
Run Code Online (Sandbox Code Playgroud)
Microsoft SQL Server 2014 (SP2-CU11) (KB4077063) - 12.0.5579.0 (X64) 
    2018 年 2 月 21 日 12:19:47 
    版权所有 (c) 微软公司
    Windows NT 6.3 (Build 9600: ) (Hypervisor) 上的开发者版(64 位)

DB 的兼容性级别为 100 (SQL 2008)。

Ran*_*est 9

这个答案取自 Paul Randal 撰写的 SQLskills.com 时事通讯的一期,关于“一个数据库会因页面校验和错误而导致备份失败,但通过了一个DBCC CHECKDB”。

唯一会发生这种情况的情况是,当扩展区是混合扩展区(其中扩展区中的 8 个页面可以分配给潜在的 8 个不同的分配单元 - 请参阅此处并且某些页面被错误地标记为由相关 PFS 页面分配时。

发生这种情况时,DBCC CHECKDB不会尝试读取这些页面,因为它会从分配单元的 IAM 页面(其中第一个列出从混合区分配的页面)派生出要读取的页面。这个案例是DBCC CHECKDB的腐败检测逻辑中的一个漏洞。

[因为]DBCC CHECKDB无法检测到损坏,因此无法进行修复所需的维修。所以使用DBCC WRITEPAGE,我直接在 PFS 页面中计算出错误分配页面的分配状态所需的更改,并且它起作用了!

这是一种极为罕见的情况 -DBCC CHECKDB 失败但备份会成功的情况更为常见。

在我看来,Paul 的解决方案远不止像您那样导出和导入数据,所以我认为您做了正确的事情。