当前位置: 首页 > 科技观察

如何在SQLServer中进行页级恢复

时间:2023-03-16 17:53:03 科技观察

今天的文章,想说说每个DBA都应该知道的一个重要话题:如何在SQLServer中进行页级恢复。假设您在SQLServer中有一个损坏的页面,并且您只想从最近的数据库备份中恢复有故障的页面,而不是恢复整个数据库。让我们破坏一个页面。首先,我想向您展示如何创建一个表(或索引)中的特定页面已损坏的场景。在这里我们将施展魔法,因为开箱即用的SQLServer本身不会引入任何损坏的页面(如果有,恭喜你发现了一个错误)。我们首先创建一个新数据库并将一些记录插入到新创建的表中。1USEmaster2GO34CREATEDATABASEPageLevelRestores5GO67USEPageLevelRestores8GO910--创建一个表,其中每条记录都适合8kb11的一页CREATETABLETest12(13FillerCHAR(8000)14)15GO1617--Insert4records18INSERTINTOTestVALUES(REPLICATE('A',8000))19INSERTINTOTestVALUES(REPLICATE('B',8000))20INSERTINTOTestVALUES(REPLICATE('C',8000))21INSERTINTOTestVALUES(REPLICATE('D',8000))22GO2324--检索选定的记录25SELECT*FROMTest26GO接下来我进行完整的数据库备份。这意味着备份包含属于测试表的所有页面。这非常重要,因为接下来我们将销毁该表的特定页。为了找出属于Test表的页面,我使用DBCCIND命令返回属于该表的所有页面。1--执行完整的数据库备份2BACKUPDATABASEPageLevelRestoresTODISK=N'C:\Backups\PageLevelRestores.bak'3GO45--检索指定表的第一个数据页(列PageFID和PagePID)6DBCCIND(PageLevelRestores,Test,-1)7GO为了销毁特定页面,我使用了未记录的DBCCWRITEPAGE命令。是的,SQLServer中有一个DBCCWRITEPAGE命令可用,但请不要告诉任何人...1ALTERDATABASEPageLevelRestoresSETSINGLE_USERWITHROLLBACKIMMEDIATE2GO34--让我们破坏第90页...5DBCCWRITEPAGE(PageLevelRestores,1,90,0,1,0x41,1)6DBCCWRITEPAGE(PageLevelRestores,1,90,1,1,0x41,1)7DBCCWRITEPAGE(PageLevelRestores,1,90,2,1,0x41,1)8GO910ALTERDATABASEPageLevelRestoresSETMULTI_USER11GO为了使用DBCCWRITEPAGE,有问题的数据库必须设置为单用户模式,如代码所示。这里我模拟了一个存储错误,向存储页面写入了一些垃圾(是的,这在你工作中也会发生!)。现在,当您再次从表中读取数据库时,SQLServer将返回824I/O错误,因为损坏页面的验证失败。1--检索选中的记录2SELECT*FROMTest3GO一旦SQLServer在I/O访问过程中检测到损坏的页面,损坏的页面也会被记录在msdb.dbo.suspect_pages中,如下图所示。1SELECT*FROMmsdb.dbo.suspect_pages监视msdb中的特定表以查看数据库中是否有损坏的页面是个好主意。现在我们把事情弄得更糟,下面的代码将向表中插入另一条记录。1--现在我们有了不想丢失的额外事务...2INSERTINTOTestVALUES(REPLICATE('E',8000))3GO让我们恢复损坏的页面现在你是DBA,你想要恢复这个数据库处于正确的状态,没有数据丢失(就像我们在上一步中插入的记录)。你会怎么做?首先你要执行一个所谓的尾日志备份(Tail-LogBackup):你要备份自上次事务日志备份以来发生的事务。1--备份事务日志2BACKUPLOGPageLevelRestoresTO3DISK='C:\Backups\PageLevelRestores_LOG1.bak'4WITHINIT5GO这里没有做事务日志备份,所以我们的备份会包含所有执行过的事务。现在我们可以在SQLServer中启动页面级恢复操作。这里使用传统的RESTOREDATABASET-SQL命令,但只需要指定要恢复的页面,而不是恢复整个数据库,我们只需要恢复有问题的页面即可。如果您处理的是非常大的数据库,这将产生很大的不同。1USEmaster2--恢复完整的数据库备份3RESTOREDATABASEPageLevelRestores4PAGE='1:90'5FROMDISK='C:\Backups\PageLevelRestores.bak'6WITHNORECOVERY7GO现在是棘手的部分:T-SQL在RESTOREDATABASE之后命令,你想做另一个事务日志备份。这个额外的日志备份是必需的,因为那时您要确保在此可用页面上所做的所有更改都可用于还原。如果没有这个额外的日志备份,SQLServer就无法使您的页面重新联机。1--备份日志尾部...2BACKUPLOGPageLevelRestoresTO3DISK='C:\Backups\PageLevelRestores_LOG_TAIL.bak'4WITHINIT5GO在进行这个额外的日志备份后,***您可以恢复所有日志备份,***您可以使数据库重新联机。1--以正确的顺序恢复所有可用的日志备份2RESTORELOGPageLevelRestoresFROM3DISK='C:\Backups\PageLevelRestores_LOG1.bak'4WITHNORECOVERY5GO67--最后恢复尾日志备份8RESTORELOGPageLevelRestoresFROM9DISK='C:\Backups\PageLevelRestores_LOG_TAIL.bak'10WITHNORECOVERY11GO1213--Finallyfinishwiththerestoresequence14RESTOREDATABASEPageLevelRestoresWITHRECOVERY15GO现在当你再次查询表时,你会看到SELECT语句执行成功,没有任何I/O错误,此表中没有数据丢失。仍然很简单,不是吗?1USEPageLevelRestores2GO34--检索选中的记录5SELECT*FROMTest6GO总结如何在SQLServer中进行页级恢复操作是每个DBA都应该知道的。它是您工具箱中最重要的工具之一——尤其是当您处理非常大的数据库时。不是恢复整个数据库,而是只恢复有问题的页面,整??个恢复过程会非常快。***读者们,这里有一个问题要问您:您是否曾经在SQLServer中进行过页面级恢复,如果是的话——这对您来说有多难/容易?请大声说!感谢关注!