zoukankan      html  css  js  c++  java
  • sql server系统页错误(GAM、SGAM、PFS)

    【1】dbcc checkdb发现错误信息

    dbcc checkdb系统页错误(GAM、SGAM、PFS)

      

    事务日志备份也全部报错

          

          

    【2】查看错误页类型信息

    【2.1】查看 msdb..suspect_pages 获取问题页类型

    SELECT DB_NAME(database_id) dbname,[file_id],page_id,
    CASE event_type
    WHEN 1 THEN '823 or 824 or Torn Page'
    WHEN 2 THEN 'Bad Checksum'
    WHEN 3 THEN 'Torn Page'
    WHEN 4 THEN 'Restored'
    WHEN 5 THEN 'Repaired (DBCC)'
    WHEN 7 THEN 'Deallocated (DBCC)'
    END event_type,
    error_count,
    last_update_date
    FROM msdb..suspect_pages

      

    【2.2】查看错误页是属于哪种系统页(PFS)

    Declare @PageID int;
    -- Enter page number
    -- e.g., 8088 = PFS page
    Set @PageID = 32352;
    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

      

    【3】无法使用dbcc checkdb repair_allow_data_loss 修复,报同样的错误

      

    【4】解决思路

    【4.0】利用备份页还原

    深入参考:https://www.cnblogs.com/gered/p/9435282.html

    SQL Server页级别的数据恢复
    --1.最近的完整备份
    BACKUP DATABASE DBName TO DISK = N'C:Test.bak'
     
    --2.发现错误页(可以人为破坏)
    SELECT * FROM msdb.dbo.suspect_pages
     
    --3.立即备份日志1
    BACKUP LOG DBName TO
    DISK = 'C:Test_LOG1.bak'
    WITH INIT
     
    --3.用完整备份,还原数据损坏的页
    USE Master
    RESTORE DATABASE DBName
    PAGE = '1:832'
    FROM DISK = 'C:Test.bak'
    WITH NORECOVERY
     
    --4.备份日志2
    BACKUP LOG DBName TO
    DISK = 'C:Test_LOG2.bak'
    WITH INIT
     
    --5.还原日志1
    RESTORE LOG DBName FROM
    DISK = 'C:Test_LOG1.bak'
    WITH NORECOVERY
     
    --6.还原日志2
    RESTORE LOG DBName FROM
    DISK = 'C:Test_LOG2.bak'
    WITH NORECOVERY
     
    --7.还原数据库状态,大工告成
    RESTORE DATABASE DBName WITH RECOVERY
     
    /*
    人为破坏数据页
    1.查看表使用的数据页
      DBCC IND(DBName, TableName, -1)
    2.修改数据库访问模式
      ALTER DATABASE DBName SET SINGLE_USER WITH ROLLBACK IMMEDIATE
    3.破坏数据页(1是PageFID,832是PagePID)
      DBCC WRITEPAGE(DBName, 1, 832, 0, 1, 0x41, 1)
    4.修改数据库访问模式
      ALTER DATABASE DBName SET MULTI_USER
    */

    【4.1】库小的时候

    把库迁移到本实例另外一个新建的库

    大概步骤:(也可以用Bcp)

    (1)如果是2008级以上

        停机=》利用右击数据库=》任务=》生成脚本     得到数据库对象架构、数据脚本

    (2)如果是2005

        停机=》利用右击数据库=》任务=》生成脚本     得到数据库对象架构脚本(不包含表数据)

        然后利用 sys.tables来进行 insert into select ......迁移数据到另外一个库

    具体操作:

    直接利用SSMS自带的生成脚本,右击数据库=》任务=》生成脚本

      

      然后选择架构和数据,相关的触发器、索引都可以。2008可以选择架构和数据,2005只能选择架构。

    但2005,只能生成架构语句,也就是 create脚本,并不能生成对应的 insert value 。

    所以2005的玩家,需要额外利用sys.tables把故障库的数据,利用 insert into select 插入到新库。

    --要使用,@new_db内容用查找替换来全部替换掉,否则会有问题的
    
    declare @old_db varchar(100),@new_db varchar(100),@sql varchar(max)
    select @old_db='[10.1.4.234].db_tank',@new_db='test2'
    
    -- 获取有自增列插入语句
    select 'use '+@new_db+';set identity_insert '+t1.name+' on;insert into '+@new_db+'.dbo.'+t1.name+'('+
    (select stuff((select',['+name+']' from test2.sys.syscolumns where id=t1.object_id for xml path('')),1,1,''))+')'+
    ' select '+(select stuff((select',['+name+']' from test2.sys.syscolumns where id=t1.object_id for xml path('')),1,1,''))
    +' from '+@old_db+'.dbo.'+t1.name+';set identity_insert '+t1.name+' off;' 
    from test2.sys.tables t1 
    where exists 
    (
    select 1 from test2.sys.columns t2 where t2.is_identity=1 and t1.object_id=t2.object_id 
    ) 
    and t1.type='u'
    
    
    -- 获取无自增列插入语句 
    
    select 'use '+@new_db+';insert into '+@new_db+'.dbo.'+t1.name+' select * from '+@old_db+'.dbo.'+t1.name+';' 
    from test2.sys.tables t1 
    where not exists 
    (
    select 1 from test2.sys.columns t2 where t2.is_identity=1 and t1.object_id=t2.object_id 
    ) 
    and t1.type='u'
    
    --------------核验--------------------
    -- 更新统计信息
    use test2
    EXEC sys.sp_updatestats
    
    use db_logs
    EXEC sys.sp_updatestats
    -- 根据聚集索引/堆对比行数
    
    use master;
    if object_id('temp1') is not null
    drop table master.dbo.temp1
    
    select t2.name tab_name,rows,indid into master..temp1 
    from [10.1.4.234].db_tank.sys.sysindexes t1 join [10.1.4.234].db_tank.sys.sysobjects t2 on t1.id=t2.id 
    where t1.indid in(0,1) and t2.type!='S'
    
    use master;
    if object_id('temp2') is not null
    drop table master.dbo.temp2
    
    select t2.name tab_name,rows,indid into master..temp2 
    from test2.sys.sysindexes t1 join test2.sys.sysobjects t2 on t1.id=t2.id 
    where t1.indid in(0,1) and t2.type!='S'
    
     
    -- 根据聚集索引/堆对比行数,筛选行数不一致的
    select t1.*,t2.*,t1.rows-t2.rows as flag from 
    master..temp1 t1 join
    master..temp2 t2 on t1.tab_name=t2.tab_name
    where t1.rows-t2.rows>0
    -- 对比表存在情况
    select t1.*,t2.*,t1.rows-t2.rows as flag from 
    master..temp1 t1 full join
    master..temp2 t2 on t1.tab_name=t2.tab_name
    where t1.tab_name is null or t2.tab_name is null

     搞完之后记得还有账户映射,权限等问题

    【4.2】库大的时候,且短时间DML不多

    (1)新建备份、快照等 构造现有时间点数据集,然后(如果是2008,使用apexsql 或 使用 cdc)(如果是2005,怕是只能使用apexsql、DML触发器 等收集增量数据)

    (2)把备份、快照等构造的时间点数据集插入到新库

    (3)然后应用增量数据

    这里比较麻烦,就不演示了

    参考文档

    SQL Server数据库损坏、检测以及简单的修复办法https://www.cnblogs.com/gered/p/13207686.html   

  • 相关阅读:
    elasticsearch的cross_fields查询
    搭建elk集群 disabled in libcurl elasticsearch-6.2.2 更新license 版本
    elastic mapping not_analyzed 简单理解 + analysis-ik分词器安装
    ElasticsearchException: java.io.IOException: failed to read [id:0, file:/data/elasticsearch/nodes/0/_state/global-0.st]
    elastic 查询案例Query与Filter + 增删改查简单理解 + dynamic mapping + keyword
    kibana 查询例子
    用grok拆分java日志
    logstash 处理信息规律研究
    docker-compose 部署elk+解决时间不对导致kibana找不到logstash定义的index + docker-compose安装
    JavaScript(6):Number对象
  • 原文地址:https://www.cnblogs.com/gered/p/12573424.html
Copyright © 2011-2022 走看看