SQL Server 對數據庫損壞的錯誤類型做了細化,在此對幾個典型的錯誤作一下介紹。
錯誤信息是:“在文件 '%ls'中、偏移量為 %#016I64x 的位置執行 %S_MSG 期間,操作系統已經向 SQL Server 返回了錯誤 %ls。”
“The operating systemreturned error %ls to SQL Server during a %S_MSGat offset %#016I64x in file '%ls'.”
例如:
Msg 823, Level 24, State 3, Line 1
The operating system returned error 5(Access is denied.) to SQLServer during a write at offset 0x0000000000e000 in file 'FilePath\FileName'.
823錯誤代表SQLServer在向操作系統申請某個頁面讀寫的時候遇到Windows讀取或寫入請求失敗。Windows返回的錯誤代碼和相應的文本會插入消息中。對於讀取操作,SQL Server在報出823錯誤之前已經重試讀取請求4次。
從錯誤產生的機制可以看出,823錯誤是發出一個頁面讀寫請求時發生的,和讀寫的內容沒有關系。所以823錯誤和SQLServer本身無關。通常是物理文件損壞導致此錯誤,但也可能是設備驅動程序導致的。如果某個數據文件上反復出現823錯誤,要不就是硬件設備出了問題,要不就是數據文件已經發生了非常嚴重的損壞。這個錯誤基本上意味着數據頁里的有效數據已經丟失,一般DBCCCHECKDB很難修復。
錯誤信息是:“SQLServer檢測到基於一致性的邏輯I/O錯誤 %ls。在文件 '%ls' 中、偏移量為 %#016I64x 的位置對數據庫 ID %d 中的頁 %S_PGID 執行 %S_MSG 期間,發生了該錯誤。”
“SQL Server detecteda logical consistency-based I/O error: %ls. It occurred during a %S_MSG of page %S_PGIDin database ID %d at offset %#016I64x in file '%ls'.”
例如:
SQL Server detected a logical consistency-based I/O error: tornpage (expected signature: 0x0; actual signature: 0x4e0372a8). It occurredduring a read of page (1:0) in database ID 13 at offset 0000000000000000 infile 'S:\Microsoft SQL Server\MSSQL.1\MSSQL\Data\www71_global_Data.mdf'.
此錯誤表明Windows報告已從磁盤成功讀取頁,但SQL Server檢測到頁中存在邏輯錯誤。那么SQLServer會檢測到哪些“邏輯錯誤”呢?常見的錯誤類型有以下幾種。
Checksum
SQL Server可以在寫入每個頁面時,根據頁面里的數據算出一個校驗值,一同存儲到頁面里去。當下次讀取頁面的時候,再根據這次讀到的頁面數據,算出一個新的校驗值。如果寫入和讀出的數據一模一樣,那么兩個校驗值一定是相等的。而如果兩個校驗值不相等,意味着上次SQLServer寫入的數據和這次讀出來的內容一定不同,現在讀出來的數據有問題。通過這種方法,SQL Server能夠發現數據頁面損壞。
TornPage
殘缺頁(Torn Page)保護其實是一種對電源故障導致的頁損壞進行檢測的方法。例如,意外電源故障可能導致一個頁面只有一部分被寫入了磁盤。使用殘缺頁保護時,頁的每個512B扇區末尾會放置一個2位簽名(在將原來的2位復制到頁頭之后)。每次進行寫操作時,這個簽名在二進制數01和10之間交替,這樣始終可以確定是否只有部分扇區寫到磁盤。如果稍后讀取頁時發現某個位的狀態不正確,則說明該頁沒有被正確寫入,因此檢測到問題頁面,稱為殘缺頁。相對於Checksum,殘缺頁檢測使用的資源最少,但是它的算法太簡單,無法檢測到磁盤硬件故障導致的所有錯誤。
ShortTransfer
讀到的數據長度比預期的少。例如,一個讀取要求預期可以讀到8KB的數據,可是實際只返回了4 KB。這也意味着當前讀到的頁面有損壞。
Bad PageId
在讀到頁面后,SQL Server會比較頁面開頭存儲的頁面編號和自己請求的目標編號。如果發現自己想要讀取的頁面是第200頁,而讀到的內容里顯示它是第100頁,SQL Server就會觸發824錯誤。這種錯誤經常是因為I/O子系統沒有正確地處理SQL Server的請求,傳給SQL Server一個錯誤的頁面,甚至是一個空頁面。
RestorePending
在SQL Server 的企業版里,用戶可以要求在做還原的時候跳過一些有損壞的頁面(continue after error)。這些跳過的頁面就被標識成“Restore Pending”。如果有用戶想去訪問它,也會遇到824錯誤。
StaleRead
一些硬件系統經常發生漏寫的現象(SQL Server要求將某個頁面寫入硬盤文件,I/O子系統報告寫入已經完成,可是SQLServer下次讀取的時候,讀到的還是寫入前的內容)。由於讀到的老版本頁面本身沒有什么問題,Checksum和Tong Page算法都不能檢查到錯誤。對這一類問題,SQLServer也有對策。在打開SQL Server啟動參數開關-T818以后,SQL Server會在內存里維護一個哈希表,記錄下自己所有做過寫入動作的頁面最新的LSN(Log Sequence Number)值。在下次讀出頁面的時候,會去比較這兩個值是否相等。由於LSN是個自動增長的唯一值,每個發生新修改的頁面,LSN的值會比原來的要大。所以如果讀到的LSN與內存中存放的不一致,就說明上次的寫入請求沒有真正完成。這時824錯誤也會被觸發。
從上面的介紹可以看出,824雖然是一個“邏輯錯誤”,是SQLServer主動發現的數據損壞,但是損壞的來源,大都不是SQL Server自己。這里的錯誤,主要是由於預期的寫入沒有完全完成導致的。所以824錯誤的原因,基本上還是在I/O子系統。由於SQL Server的讀寫請求是發給Windows,再由Windows發給底層的磁盤系統的,所以問題有可能發生在Windows以下的每一層,例如磁盤驅動器存在故障、磁盤固件存在問題、設備驅動程序不正確等。可以負責任地說,SQLServer自己是不會導致824錯誤的。
由於824錯誤是發生在頁面這一級的邏輯錯誤,所以很多時候DBCC CHECKDB能夠修復。但是這種修復也僅僅是邏輯上的,頁面里面存儲的數據在824錯誤發生之前就已經丟失,SQL Server無法將它們修復回來。所以824錯誤基本也意味着部分數據丟失。
錯誤信息是:“嘗試在數據庫%d 中提取邏輯頁 %S_PGID 失敗。該邏輯頁屬於分配單元%I64d,而非 %I64d。”
“Attempt to fetchlogical page %S_PGIDin database %d failed. It belongs to allocation unit %I64d not to %I64d.”
例如:
Attempt to fetch logical page (1:584) in database 2 failed. Itbelongs to allocation unit 445237904015360 not to 72057594060079104.
605也是一個非常有名的數據庫損壞錯誤。此錯誤通常表示指定數據庫中的頁或分配已損壞。SQLServer會在根據頁鏈接或使用索引分配映射(IAM)讀取屬於表的頁時,檢測到此損壞。分配給表的所有頁必須屬於與該表相關聯的分配單元之一。如果頁眉中包含的分配單元ID不匹配與表相關聯的分配單元ID,將引發此異常。錯誤消息中列出的第一個分配單元ID是頁眉中顯示的ID,而第二個分配單元值則是與表相關聯的ID。
嚴重級別為21表示可能存在數據損壞。造成的原因包括損壞的頁鏈、損壞的IAM或該對象的sys.objects目錄視圖中存在無效條目。這些錯誤通常由硬件或磁盤設備驅動程序故障而引起。
嚴重級別為12表示可能存在暫時性錯誤,即在緩存中出現錯誤,但不表示對磁盤上的數據造成破壞。暫時性的605錯誤可由以下條件引發:
· 操作系統過早地通知SQL Server已完成某個I/O操作;盡管不存在實際的數據損壞,但顯示錯誤消息。
· 運行帶有優化器提示NOLOCK的查詢,或將事務隔離級別設置為READ UNCOMMITTED。當使用NOLOCK或READ UNCOMMITTED的查詢嘗試讀取被其他用戶移走或更改的數據時,將發生605錯誤。若要驗證是否為暫時性的605錯誤,可以稍后重新運行該查詢。
通常,如果在數據訪問期間發生該錯誤,但后續的DBCCCHECKDB操作在沒有出錯的情況下完成,則605錯誤可能是暫時的。
由於605這個錯誤意味着一些頁面分配出了問題,所以也是一個非常嚴重的數據庫損壞。一般用DBCC CHECKDB也很難修復。
其他
在SQL Server內部,除了文件頁面分配和每個頁面內部格式以外,還有一些其他的約束規則。下面是一些常見的錯誤例子。
PFS頁面頭有損壞:
Msg 8946, Level 16, State 12, Line 1Table error: Allocation page(1:13280496) has
invalid PFS_PAGEpage header values.Type is 0. Check type, alloc unit ID and page
ID on the page.
系統表上的聚集索引頁面上有損壞:
Server: Msg 8966, Level 16, State 1, Line 1 Could not read andlatch page (1:18645)
with latch type SH. sysindexes failed.
Msg 7985, Level 16, State 2, Server SUNART, Line 1System tablepre-checks: Object
ID 4. Could not read and latch page (1:51) withlatch type SH. Checkstatement
terminated due to unrepairable error.
某個字段的值不符合字段數據類型定義:
Msg 2570, Level 16, State 3, Line 1Page (1:152), slot 0 in objectID 2073058421,
index ID 0, partition ID 72057594038321152, alloc unit ID72057594042318848 (type
"In-row data"). Column "c1" value is out ofrange for data type "datetime". Update
column to a legal value.
元數據有損壞:
Msg 3854, Level 16, State 1, Line 2Attribute (referenced_major_id=2089058478)of
row (class=0,object_id=2105058535,column_id=0,referenced_major_id=2089058478,referenced_
minor_id=0)in sys.sql_dependencies has amatching row (object_id=2089058478)in
sys.objects (type=SN) that is invalid.
遇到這些錯誤,管理員需要用DBCCCHECKDB命令來檢查和修復。有些錯誤是可以不丟數據就能修復的,有些是要丟數據才能修復物理層面錯誤的,有些是即使丟數據也沒辦法修復的。現在就來介紹CHECKDB的使用技巧。