zoukankan      html  css  js  c++  java
  • 【SQL Server备份恢复】数据库恢复:对page header的恢复

    前两天在论坛,看到有个网友提问,说是:

    格式化磁盘前把.mdf和.ldf拷贝出来了,然后格式化完成后在拷贝回去(拷贝前后都没有错误提示,文件大小也一样),在企业管理器中附加数据库出错,提示“错误823”,附加数据库失败。从网上搜了搜方案:重建同名数据库之类的做法都试过了,都不能解决问题。请问版主或各位高手,有什么解决方案吗?
    注:拷贝之前数据库使用正常,并且以前都是此种方法附加的,这次不知如何出现这样的问题了。


    帮他尝试恢复:

    1、他已经按照网上的方法,新建了一个同名的数据库。


    2、停止服务,然后把原始的文件拷贝到目录中。


    3、启动服务,发现数据库处于质疑状态。


    4、运行如下命令,都报错:打不开数据库

    dbcc checkdb(xxx);
    
    dbcc checkdb(xxx,repair_allow_data_loss);


    5、运行如下命令成功, 设置数据库为紧急模式  

     Use Master  
     GO  
     
     sp_configure 'allow updates', 1  
     reconfigure with override  
     GO  
     
     UPDATE sysdatabases SET status = 32768 where name = 'xxx'  
     GO  


    6、再次运行命令,报错:数据库必须处于单用户模式

    dbcc checkdb(xxx,repair_allow_data_loss);


    7、如果如下命令,设置数据库为单用户模式:

    alter database test set single_user


    8、再次运行命令,还是报错:数据库必须处于单用户模式

    dbcc checkdb(xxx,repair_allow_data_loss);


    在这里就觉得很奇怪,明明已经设置为单用户模式了,怎么还报这个错误呢?

    在网上找了一下,发现有很多人都有这个问题,但是没有解决办法。


    9、尝试运行如下命令,但类似这样的报错:

    服务器: 消息 8909,级别 16,状态 1,行 1
    表错误: 对象 ID 0,索引 ID 0,页 ID 0。
     服务器: 消息 8966,级别 16,状态 1,行 1
    未能读取并闩锁页 (1:123456)(用闩锁类型 SH)。sysobjects 失败。


    在网上找到一篇文章:

    sql server 系统表损坏修复方法 http://wenku.baidu.com/view/901cd511f18583d04964592e

    这个文章中提到的解决方法就是,新建一个数据库,通过dts,把原来数据库的数据,导出到新的数据库中,但前提是其中的表都能访问,也就是能够select * from 表,否则就没用了。


    那么有没有什么好的办法,能修复呢?

    在网上找了一下,发现有专业的数据恢复公司,能恢复这种错误,从文章中提到的信息来看,应该通过直接构造损坏的页面来修复的。


    由于这种情况比较难重现,所以这里模拟当某个数据页的page header损坏时,如何手动修复这个数据页,其实就是一个复制粘帖的过程。


    1、先创建一个数据库,创建表,插入数据:

    create database w
    go
    
    use w
    go
    
    
    if OBJECT_ID('test') is not null
       drop table test
    
    select * into test
    from sys.objects
    go
    
    
    insert into test
    select * 
    from test
    


    2、分离数据库w,把数据文件和日志文件,直接复制到一个备份目录。


    3、本来通过dbcc writelog来修改数据,但是应该是没有修改好。

    dbcc writepage的语法为:
    
    dbcc writepage 
    ({ dbid,'dbname' }, fileid, pageid, offset, length, data)
    
    
    --生成96个字节的数据
    select '0x'+replicate('00',96)
    
    dbcc writepage('w',1,310,0,96,
    0x000000000000000000000000000000000000000
    00000000000000000000000000000000000000000
    00000000000000000000000000000000000000000
    00000000000000000000000000000000000000000
    000000000000000000000000000000)
    /*
    消息 8939,级别 16,状态 5,第 1 行
    表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 (0:0)。测试(m_headerVersion == HEADER_7_0)失败。值为 0 和 1。
    消息 8939,级别 16,状态 6,第 1 行
    表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 (0:0)。测试((m_type >= DATA_PAGE && m_type <= UNDOFILE_HEADER_PAGE) || (m_type == UNKNOWN_PAGE && level == BASIC_HEADER))失败。值为 0 和 0。
    消息 8939,级别 16,状态 7,第 1 行
    表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 (0:0)。测试(m_freeData >= PageHeaderOverhead () && m_freeData <= (UINT)PAGESIZE - m_slotCnt * sizeof (Slot))失败。值为 0 和 8192。
    DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
    */


    所以,改用二进制编辑工具,输入:0x0026C000,定位到这个物理偏移,然后修改了数据库w中的fileID为1,pageID为310的,前96个字节全为00,这个正好是page header部分:

    select 8*1024*310 as '310页在文件中的物理偏移',
           CAST(8*1024*310 as varbinary)  '转化为16进制'
    /*
    310页在文件中的物理偏移	转化为16进制
    2539520	0x0026C000
    */





    4、重新附加这个数据库

    dbcc checkdb(w)
    /*
    消息 8909,级别 16,状态 1,第 1 行
    表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 0 (类型为 Unknown),页 ID (1:310) 在其页头中包含错误的页 ID。页头中的 PageId = (0:0)。
    CHECKDB 发现有 0 个分配错误和 1 个一致性错误与任何单个的对象都没有关联。
    
    消息 8928,级别 16,状态 1,第 1 行
    对象 ID 981578535,索引 ID 0,分区 ID 72057594038910976,分配单元 ID 72057594042580992 (类型为 In-row data): 无法处理页 (1:310)。有关详细信息,请参阅其他错误消息。
    
    CHECKDB 在数据库 'w' 中发现 0 个分配错误和 2 个一致性错误。
    对于由 DBCC CHECKDB (w)发现的错误,repair_allow_data_loss 是最低的修复级别。
    DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。
    */
    


    5、把数据库分离,从备份的文件中,复制page header到这个文件



    6、再次附加数据库,就可以查询了。

    不过,使用repair_allow_data_loss也可以恢复。


  • 相关阅读:
    如何:通过对字符串应用 HTML 编码在 Web 应用程序中防止脚本侵入
    ref和out的区别?
    debug版本和release版本的区别?
    Ninject依赖注入——构造函数的注入
    WCF入门简单教程(图文) VS2010版
    WCF学习笔记(一)
    WinRt BottomAppBar
    windows 8.1 MessageDialog
    sqlServer学习2-sql脚本说明
    sqlServer学习1-sql脚本
  • 原文地址:https://www.cnblogs.com/momogua/p/8304517.html
Copyright © 2011-2022 走看看