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.-1】嘗試直接修復(DBCC CHECKALLOC(dbname,REPAIR_ALLOW_DATA_LOSS ))

DBCC CHECKALLOC   
[  
    ( database_name | database_id | 0   
      [ , NOINDEX   
      | , { REPAIR_ALLOW_DATA_LOSS | REPAIR_FAST | REPAIR_REBUILD } ]  
    )  
    [ WITH   
        {   
          [ ALL_ERRORMSGS ]  
          [ , NO_INFOMSGS ]   
          [ , TABLOCK ]   
          [ , ESTIMATEONLY ]   
        }  
    ]  
]  

該命令官網:https://docs.microsoft.com/zh-cn/sql/t-sql/database-console-commands/dbcc-checkalloc-transact-sql?view=sql-server-ver15

【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】可能發生了架構損壞。請運行DBCC CHECKCATALOG.

參考文檔

SQL Server數據庫損壞、檢測以及簡單的修復辦法

https://www.cnblogs.com/gered/p/13207686.html   

【sql server】可能發生了架構損壞。請運行DBCC CHECKCATALOG.

參考:DBCC IND https://www.cnblogs.com/gered/p/9444344.html#autoid-3-0-0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM