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