博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

说明:灾难恢复系列的文章是由 Robert Davis 写的,发布在SQLSoldier 个人认为挺不错的,所以根据自己的理解,边测试边整理,并非直接翻译,如有不准确,欢迎指正。

本篇进入数据库灾难恢复第五篇,上一篇演示了修复简单的非聚集索引损坏,今天,我们将看一个稍复杂点儿的,那就是管理区分配页损坏,不过分配页无法修复,只能恢复整个数据库。

什么是管理区分配页
管理区分配页是数据文件中特殊的页,用来跟踪和管理区分配,本篇将关注三种:

全局分配映射表 (GAM):记录已分配的区,对于一个数据文件,每4GB会有一个GAM页,它的ID总是为2,之后每511,232页出现一次。
        Page ID = 2 or Page ID % 511232

共享全局分配映射表 (SGAM) :记录当前用作混合区且至少有一个未使用的页的区,每4GB会有一个SGAM页,它的ID总是为3,之后每511,232页出现一次。
       Page ID = 3 or (Page ID – 1) % 511232

页可用空间 (PFS):记录每页的分配状态,是否已分配单个页以及每页的可用空间量,每64MB会有一个PFS页,它的ID总是为1,之后每8,088页出现一次。
       Page ID = 1 or Page ID % 8088

如果PAGE id是1/2/3,那么很明显会知道他们是什么管理区分配页,如果PAGE ID很大,那么我们有两个办法来区分它们:

一个办法是采用SQL脚本计算:

Declare @PageID int;

-- Enter page number
-- e.g., 8088 = PFS page
Set @PageID = 8088;

Select Case
    When @PageID = 1 Or @PageID % 8088 = 0 Then 'Is PFS Page'
    When @PageID = 2 Or @PageID % 511232 = 0 Then 'Is GAM Page'
    When @PageID = 3 Or (@PageID - 1) % 511232 = 0 Then 'Is SGAM Page'
    Else 'Is Not PFS, GAM, or SGAM page'
    End

另一个办法是采用DBCC PAGE来看它的m_type值:

现在按照下面的步骤:
现在我们已经知道哪些是管理区分配页,接下来依然按三个步骤进行:

1.确定损坏(使用DBCC CHECKDB)
2.确定损坏的对象及对象类型(如索引页、分配页等)
3.确定适合的修复方法



确定损坏
首先,请先下载一个PFS损坏的数据库,然后运行DBCC CHECKDB:

DBCC CheckDB(PFSCorruption)
    With No_InfoMsgs, All_ErrorMsgs, TableResults;

由于返回太多我们不需要的列,为了更好的体现这里的演示效果,减去一些列,不过在实际做故障排除时,还是要用返回全部列,这里仅为了演示:

Declare @DBCC Table (
    Error int,
    Level smallint,
    State tinyint,
    MessageText varchar(2500),
    RepairLevel varchar(30) null,
    Status tinyint,
    DbId int,
    DbFragId int,
    ObjectId int,
    IndexId int,
    PartitionId bigint,
    AllocUnitId bigint,
    RidDbId int,
    RidPruId int,
    [File] int,
    Page int,
    Slot int,
    RefDbId int,
    RefPruId int,
    RefFile int,
    RefPage int,
    RefSlot int,
    Allocation bigint)

Insert Into @DBCC
Exec sp_executesql N'DBCC CheckDB(PFSCorruption)
    With No_InfoMsgs, All_ErrorMsgs, TableResults;';

Select Level,
    State,
    MessageText,
    RepairLevel,
    ObjectId,
    IndexId,
    [File],
    Page,
    RefFile,
    RefPage
From @DBCC;

结果:

确定损坏的对象
这一步我们需要确定真正的错误,可以看到有较高级别的错误号16,这是需要我们要仔细查的,另外State列为5表示一个未知的错误导致DBCC CHECKDB终止执行,另外这两行中不同的pageid(1:6)和(1:7)可能会误导你以为是他俩是损坏的页,但实际上是(1:1)中有这两个错误page值而已,所以需要关注的是RefFile和RefPage这两个列,而不是File和Page列。

从上面DBCC CHECKDB的结果,可以直接看出是PFS页面,所以不需要记算也不需要DBCC PAGE去判断,因为DBCC的结果是很明显的了。

采用适合的方法
在开头的时候我们已经说过管理区分配页不能被修复或还原,所以我们不得不做整个数据库的还原,那就需要检查备份的情况,尤其是事务日志备份到什么时间,然后开始做还原,如果没有备份,则需要将数据导到一个新建的数据库中。如果你能手动用一个十六进制的编辑器手动修复它(不是NB就是DS),那么最好先copy出一份来做这个操作。 

总结
本篇主要还是在讲述如何确定具体的损坏对象,主要是确定管理区分配页GAM/SGAM/PFS页,不过遗憾的是它们都无法直接修复。

下载本篇示例的数据库及代码

SQL Server 灾难恢复31天之第7天:灾难恢复服务等级协议(数据恢复点目标和数据恢复时间点目标)