在今天的文章中,我想讲一个每个DBA都应该知道的重要话题:如何在SQLServer中进行页面级还原 *** 作。假设您在SQLServer中有一个损坏的页面,并且您希望从最新的数据库备份中仅恢复损坏的页面,而不是恢复整个数据库。
让我们销毁一页
第一步,我想向您展示如何创建一个特定页面在表(或索引)中损坏的情况。这里我们将施一些魔法,因为开箱即用的SQLServer本身不会引入任何损坏的页面(恭喜您找到了一个BUG,如果有的话)。我们首先创建一个新数据库,并将一些记录插入到新创建的表中。
1USEmaster2GO 3 4CREATEDATABASEPageLevelRestores5GO 6 7USEPageLevelRestores8GO 9 10--Createatablewhereeveryrecordfitsonto1pageof8kb 11CREATETABLETest12(13FillerCHAR(8000)14)15GO 16 17--Insert4records 18INSERTINTOTestVALUES(REPLICATE('A',8000))19INSERTINTOTestVALUES(REPLICATE('B',8000))20INSERTINTOTestVALUES(REPLICATE('C',8000))21INSERTINTOTestVALUES(REPLICATE('D',8000))22GO 23 24--Retrievetheselectedrecords 25SELECT*FROMTest26GO接下来,我将进行完整的数据库备份。也就是说,这个备份包含了属于Test表的所有页面。这一点非常重要,因为这样我们就会销毁这个表的某个特定页面。为了找到属于Test表的页面,我使用DBCCIND命令返回属于这个表的所有页面。
1--Performafulldatabasebackup 2BACKUPDATABASEPageLevelRestoresTODISK=N'C:\Backups\PageLevelRestores.bak' 3GO 4 5--Retrievethefirstdatapageforthespecifiedtable(columnsPageFIDandPagePID) 6DBCCIND(PageLevelRestores,Test,-1)7GO为了销毁特定的页面,我使用了未发布的DBCCWRITEPAGE命令。是的,SQLServer中有一个DBCCWRITEPAGE命令,但请不要告诉任何人...
1ALTERDATABASEPageLevelRestoresSETSINGLE_USERWITHROLLBACKIMMEDIATE2GO 3 4--Let'scorruptpage90... 5DBCCWRITEPAGE(PageLevelRestores,1,90,0,1,0x41,1)6DBCCWRITEPAGE(PageLevelRestores,1,90,1,1,0x41,1)7DBCCWRITEPAGE(PageLevelRestores,1,90,2,1,0x41,1)8GO 9 10ALTERDATABASEPageLevelRestoresSETMULTI_USER11GO为了使用DBCC写页面,问题数据库必须设置为单用户模式(单用户模式),如代码所示。在这里,我模拟了一个存储错误,在存储的页面中写入了一些垃圾(是的,在你的工作中也会出现这种情况!)。现在,当您再次从表中读取数据库时,SQLServer将向您返回一个824I/O错误,因为损坏页面的检查失败了。
1--Retrievetheselectedrecords 2SELECT*FROMTest3GO
一旦SQLServer在I/O访问期间检测到损坏的页面,损坏的页面也会被记录在msdb.dbo.suspect_pages中,如下图所示。
1SELECT*FROMmsdb.dbo.suspect_pages
监视msdb中的特定表是一个好主意,您可以发现数据库中是否有损坏的页面。现在让事情变得更糟。下面的代码将在表中插入另一条记录。
1--Nowwehaveadditionaltransactionthatwedon'twanttoloose... 2INSERTINTOTestVALUES(REPLICATE('E',8000))3GO
让我们恢复损坏的页面
现在您是一名DBA,您希望将这个数据库恢复到正确的状态,而不丢失数据(就像我们在上一步中插入的记录)。你会怎么做?首先你要做所谓的尾日志备份)/s2/]:你要备份自上次事务日志备份以来发生的事务。
1--Backupthetransactionlog 2BACKUPLOGPageLevelRestoresTO 3DISK='C:\Backups\PageLevelRestores_LOG1.bak' 4WITHINIT5GO这里没有事务日志备份,因此我们的备份将包括自完整备份以来执行的所有事务。现在,我们可以在SQLServer中启动页面级还原 *** 作。这里您使用传统的T-SQL命令RESTOREDATABASE,但是您只需要指定要恢复的页面,而不是恢复整个数据库,我们只需要恢复有问题的页面。如果您正在处理一个大型数据库,这将会有很大的不同。
1USEmaster2--Restorefulldatabasebackup 3RESTOREDATABASEPageLevelRestores4PAGE='1:90' 5FROMDISK='C:\Backups\PageLevelRestores.bak' 6WITHNORECOVERY7GO现在到了棘手的部分:在RESTOREDATABASE的T-SQL命令之后,您必须进行另一次事务日志备份。这个额外的日志备份是必要的,因为您必须确保在这个可用页面上所做的所有更改都用于恢复。没有这种额外的日志备份,SQLServer无法将您的页面重新联机。
1--Backupthetailofthelog... 2BACKUPLOGPageLevelRestoresTO 3DISK='C:\Backups\PageLevelRestores_LOG_TAIL.bak' 4WITHINIT5GO在这个额外的日志备份之后,您最终可以按照正确的顺序还原所有的日志备份,并且最终可以使数据库重新联机。
1--Restoreallavailablelogbackupsinthecorrectorder 2RESTORELOGPageLevelRestoresFROM 3DISK='C:\Backups\PageLevelRestores_LOG1.bak' 4WITHNORECOVERY5GO 6 7--Finallyrestorethetaillogbackup 8RESTORELOGPageLevelRestoresFROM 9DISK='C:\Backups\PageLevelRestores_LOG_TAIL.bak' 10WITHNORECOVERY11GO 12 13--Finallyfinishwiththerestoresequence 14RESTOREDATABASEPageLevelRestoresWITHRECOVERY15GO现在,当您再次查询该表时,您将看到SELECT语句已成功执行,没有任何I/O错误,并且该表中没有任何数据丢失。还是很简单的,不是吗?
1USEPageLevelRestores2GO 3 4--Retrievetheselectedrecords 5SELECT*FROMTest6GO摘要
每个DBA都应该知道如何在SQLServer中执行页面级恢复。它是您工具箱中最重要的工具之一——尤其是当您处理大型数据库时。您只需要恢复有问题的页面,而不是恢复整个数据库,整个恢复过程将会非常快。
女士们、先生们,最后一个问题是:您曾经在SQLServer中进行过页面级恢复吗?如果是,对您来说有多困难/简单?请畅所欲言!
感谢您的关注!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)