■ 河南 劉景云
某單位網站后臺使用的SQL Server 2016數據庫,近來出現運行故障。
SQL Server提示出現編號為824,級別24的錯誤,檢測到基于一致性的邏輯I/O錯誤pageid不正確(應為 10:910,但實際為 0:0)。在文件 'G:dataxxx.ndf' 中,偏移量為0x00000000720000的位置對數據庫ID 5中的頁(10:910)執(zhí)行讀取期間發(fā)生了該錯誤。
SQL Server錯誤日志或系統事件日志中的其他消息可能提供了更詳細信息,這是一個威脅數據庫完整性的嚴重錯誤條件,必須立即糾正。執(zhí)行完整的數據庫一致性檢查(DBCC CHECKDB),此錯誤可以由許多因素導致。
根據以上提示信息,可以看出這是一個典型錯誤,說明SQL Server中的某些頁出現了錯誤,這導致了數據無法正常訪問的問題。
在進行修復之前,需要了解頁的損壞情況,如果損壞比較嚴重,那么頁還原是沒有什么效果的。如果頁損壞并不嚴重(一般在10個以內),那么恢復效果就比較好。
在正常情況下,數據庫的頁不會無端損壞,之所以出現頁損壞,根本原因是存儲出現了問題,例如硬盤出現壞道等。對于這種情況,首先需要檢查磁盤狀態(tài),執(zhí)行數據庫的備份操作,并將備份數據保存到安全的位置。
對頁損壞情況要進行嚴密監(jiān)控,如果其持續(xù)發(fā)生,就必須立即更換存儲設備。想了解頁損壞情況,可以在Microsoft SQL Server Management Studio中選擇目標數據庫,在工具欄上點擊“新建查詢”按鈕,執(zhí)行“dbcc checkdb”命令,檢查該數據庫的頁情況。如果數據庫比較大,檢測時間就會較長,并導致IO繁忙影響到用戶的使用速度。因此,最好在維護窗口中進行檢查。當檢測完畢,會顯示發(fā)現的錯誤信息,并且以紅色表示頁損壞信息(包括頁編號等)。
也可以執(zhí)行“select *from msdb.dbo.suspect_pages”命令。利用指定的系統視圖,來快速檢測頁損壞情況。執(zhí)行“dbcc ind('websitedb','product',1);”命令,用于定位到表或索引使用的Page信息,其中的“websitedb”表示網站數據庫名稱,“product”表示其中某張表的名稱,“1”參數表示表的聚集索引。
要想查看頁中的數據,需要先執(zhí)行“dbcc traceon(3604);”命令,來打開指定的跟蹤代碼。之后才可以執(zhí)行“dbcc page('websitedb ',1,910,3);”命令,來查看指定的頁中的數據,這里的頁號為“910”具體頁號可以從錯誤提示信息中得到。
除了使用上述檢測方法外,還可以使用“EXEC sys.sp_helpdb @dbname=pratice”,“USE pratice”,“XEC sys.sp_helpfile”命令,得到目標數據庫的ID和數據庫文件ID。執(zhí)行“DBCC TRACEON(3604,-1)”,“DBCC PAGE(16,1,10,3)”“DBCC PAGE(16,1,910,3)”命令,分別檢測發(fā)生問題的數據頁面和索引頁面,其中的“16”位目標數據庫的ID,“10”和“910”位具體的索引頁面和數據頁面,根據返回信息,可以查看對應頁面詳細信息。
因為事先管理員對數據庫進行了完整備份,所以修復起來就比較輕松了。SQL Server頁還原需要使用完整恢復模式,在執(zhí)行頁修復時,需要遵循一定的步驟。
首先從完整備份來還原頁,注意要指定頁編號。之后應用最近的差異備份和后續(xù)日志備份,這幾個步驟和日常的還原沒有區(qū)別。接下來備份當前日志,目的是重做事務日志序列號LSN,最后還原當前日志。
首先執(zhí)行“Restore headeronly from disk='E:DataWebsitedb.bak';”命令,檢測備份文件的詳細信息。例如,在其中的“BackupStartDate”和“BackupFinishDate”列中顯示備份的時間點,如果起先于頁損壞的話,就可以用來進行修復。執(zhí)行“RESTORE DATABASE websitedb PAGE='10:910' FROM disk=' E:DataWebsitedb.bak ' WITH FILE=1,NORECOVERY;”命令,執(zhí)行恢復備份文件操作,其中“E:DataWebsitedb.bak”為備份文件路徑。
然后執(zhí)行“RESTORE LOG websitedb FROM disk='E:DataWebsitedb.bak 'WITH FILE=2,NORECOVERY;”命令,執(zhí)行日志還原操作。執(zhí)行“BACKUP LOG websitedb TO disk='E:Data WebsiteTail.trn'--WITH NO_TRUNCATE;”命令,重做事務日志序列號LSN。執(zhí)行“RESTORE LOG websitedb FROM disk=' E:Data WebsiteTail.trn 'WITH FILE=1,RECOVERY;”,“Go”命令,還原當前日志。這樣,就修復了損壞的頁。
如果沒有完整備份,那么恢復起來就比較繁瑣了。如果僅僅是索引頁出現問題,可以先Drop索引,之后再創(chuàng)建索引即可修復,這不會造成任何數據損失。如果是數據頁出現問題,就需要確定發(fā)生錯誤的頁面屬于哪一個數據表,可以執(zhí)行“SELECT s.name AS N'架構名' o.name AS N'表名'FROM sys.sysobjects o INNER JOIN sys.schemas s ON o.uid=s.schema_id WHERE o.id=xxx”命令,來找到對應的數據表。
“xxx”為“ObjectID”的值,在執(zhí)行上述DBCC PAGE(16,1,10,3)”命令時,在返回信息中的“Metadata:ObjectId=”會顯示具體數值。找到目標數據表后,即可將內容導出。
具體操作時不用新建數據庫,只需在原來數據庫下新建文件組和數據文件即可。方法是在新文件組里重建損壞的表,即新建的表屬于新建的文件組,表結構要跟損壞的表完全一致,并將上述原始表數據導入到新表中,最后清空原始表。