前言:數據庫越大,使用時間越長,貌似穩定性也在逐步下降。數據頁邏輯錯誤,可能是DBA遇到比較棘手的問題之一,本文將基于實戰模式給出一些檢查及處理的方法。當然,任何方法都是受制于環境的限制,本文中介紹的方法也只適用于某些特定環境,僅供參考;
===================華麗麗的分割線========================
前幾天碰到一個錯誤,具體信息如下:
SQL Server 檢測到基于一致性的邏輯 I/O 錯誤 pageid 不正確(應為 6:49413777,但實際為 0:0)。在文件 'M:/SQLDATA/Pk_4.ndf' 中、偏移量為 0x00005e3fd22000 的位置對數據庫 ID 5 中的頁 (6:49413777) 執行 讀取 期間,發生了該錯誤。SQL Server 錯誤日志或系統事件日志
或許這是DBA遇到比較棘手的問題之一了。萬幸的是,發生錯誤的數據庫是一個事務復制環境中的訂閱庫,而且有負載均衡扛著,基本上對業務沒有影響;
1、發現該錯誤后,第一反應是存儲(樓主的土豪公司用的是IO卡)出現邏輯錯誤,嘗試手動重啟服務器,讓IO卡進行自檢;進入系統后,發現問題沒有解決;
這一步,在IO卡自檢完成進入系統后,需要進一步使用廠商提供的監控程序檢查IO卡是否有物理壞塊,并收集相關日志。經過其他同事檢查,IO卡沒有異常報錯;
2、通過我們的監控工具定位到publication是位于Publisher_A的pk_order_BEQ_new,該publication中涉及3個表
Order_A / Order_B / Order_C
3、在出現問題的機器上(以下稱為subscriber_A)通過select count(1) from table_name(nolock)的方式快速檢測具體是哪個表有問題;
此處的檢測方法有局限性,初步分析如下:
a) 如果是小表,可能在頁損壞之前有類似操作,導致全部頁還在緩存區中,因而select count(1)是可以獲取結果的,無法判斷出該表是否存頁損壞;
b) 如果IAM頁中還有6:49413777的信息,且該頁還在緩存區中,也是無法判斷出該表是否存頁損壞;
c) 如果IAM頁中沒有6:49413777的信息,則select count(1)的時候會跳過已損壞的頁,仍然可以獲取結果,也是無法判斷出該表是否存頁損壞;
只有當IAM頁中有6:49413777的信息,而該頁又被交換出緩存區,需要進行物理讀的時候,才會導致select count(1)無法獲取結果,具體情況如下:
此處檢測 Order_A正常,Order_B報錯;但這只能證明Order_B表確實存在損壞的頁,而Order_A卻不能斷定一定是正常的;
當時的檢測辦法只是按照select count(1)的方式,判斷出Order_B表存在壞頁;但實際上,可以從Publisher_A的distribution.dbo.msrepl_errors中獲取當前由復制引起的無法寫入損壞頁的XACT_Seqno,進而通過sp_browsereplcmds ‘XACT_Seqno’,’ XACT_Seqno’,及command_id定位到具體引起該錯誤的對象名、操作類型和主鍵值;
但此方法也有弊端,由于頁中可能存在多條記錄,如果是頁頭損壞,將導致該頁中的所有記錄都無法讀取,而msrepl_errors重試間隔大約1分鐘,所以通過此方法確定損壞的數據頁較慢;
4、通過distribution.dbo.msrepl_errors定位到orderexpend_pop表也存在損壞頁,并定位到是由delete操作發現異常,因此修改subscriber_A上相應的復制存儲過程;
之前采用的僅屏蔽掉IF部分的做法在此處并不適用,因為delete時的返回信息并不再是“影響0行記錄”,而是由于頁損壞導致記錄無法找到并刪除;
delete [dbo].[Order_A]where [Id] = @pkc1--if @@rowcount = 0-- if @@microsoftversion>0x07320000-- exec sp_MSreplraiserror 20598
此處為了方便后面定位可能出現的損壞頁,修改存儲過程如下:
先創建記錄表monitor.dbo.tmp_byxl_Order_A_20140428
--CREATE TABLE monitor.dbo.tmp_byxl_Order_A_20140428 (id BIGINT,checkdate DATETIME DEFAULT GETDATE())--再修改存儲過
新聞熱點
疑難解答