淺析數(shù)據(jù)庫(kù)頁(yè)損壞或出錯(cuò)時(shí)的處理方法
在管理數(shù)據(jù)庫(kù)時(shí)很容易出現(xiàn)問(wèn)題,但是出現(xiàn)數(shù)據(jù)庫(kù)頁(yè)損壞或校驗(yàn)錯(cuò)誤時(shí)該如何解決,這也是大家需要了解的重要內(nèi)容。
最近一直在進(jìn)一步學(xué)習(xí)數(shù)據(jù)庫(kù)故障的處理方面的知識(shí),做為一個(gè)數(shù)據(jù)庫(kù)維護(hù)人員,我即期望遇到所有的數(shù)據(jù)庫(kù)出錯(cuò)的案例,以增加自己的經(jīng)驗(yàn),但同時(shí)又擔(dān)心遇到這樣或那樣無(wú)法處理的數(shù)據(jù)庫(kù)故障而導(dǎo)致數(shù)據(jù)丟失。
前幾天看到一個(gè)文章,是說(shuō)一個(gè)網(wǎng)站管理員在招聘DBA時(shí),提出一個(gè)問(wèn)題:“如果在SQL Server 日志里發(fā)現(xiàn)一個(gè)頁(yè)損壞或是校驗(yàn)和錯(cuò)誤應(yīng)該如何處理?”網(wǎng)站管理員描述,大概有90%的應(yīng)聘者都會(huì)采用一個(gè)方案,用DBCC CHECKDB加上其中的一個(gè)修復(fù)選項(xiàng),但其中也基本沒(méi)有人能具體解釋DBCC CHECKDB修復(fù)的過(guò)程或是工作原理及能修復(fù)到什么程度。
借助聯(lián)機(jī)文檔以及個(gè)人的一些理解和經(jīng)歷,解釋一下如何面對(duì)這個(gè)問(wèn)題:"當(dāng)數(shù)據(jù)庫(kù)頁(yè)損壞或校驗(yàn)和出錯(cuò)時(shí)如何處理?"
首先,需要先了解DBCC CHECKDB,聯(lián)機(jī)文檔url:
http://technet.microsoft.com/zh-cn/library/ms176064.aspx
通過(guò)聯(lián)機(jī)文檔,可以得知有REPAIR_ALLOW_DATA_LOSS | REPAIR_FAST | REPAIR_REBUILD三個(gè)修復(fù)選項(xiàng),而提供實(shí)際功能的只有REPAIR_ALLOW_DATA_LOSS和REPAIR_REBUILD兩個(gè),其 中REPAIR_ALLOW_DATA_LOSS 嘗試修復(fù)報(bào)告的所有錯(cuò)誤,這些修復(fù)可能會(huì)導(dǎo)致一些數(shù)據(jù)丟失;而且REPAIR_REBUILD執(zhí)行不會(huì)丟失數(shù)據(jù)的修復(fù),包括快速修復(fù)(如修復(fù)非聚集索引中 缺少的行)以及更耗時(shí)的修復(fù)(如重新生成索引);可見(jiàn)REPAIR_REBUILD是我們期望的。
當(dāng)你從SQL Server log里或是在程序查詢數(shù)據(jù)庫(kù)或是定期通過(guò)DBCC CHECKDB為數(shù)據(jù)庫(kù)做體檢的時(shí)候,出現(xiàn)了頁(yè)損壞或校驗(yàn)和出錯(cuò)信息時(shí),如:
- ---------------------------------------------------------------------------------------------------------------------------------
- M8928sg , Level 16, State 1, Line 1
- Object ID 2088535921, index ID 0, partition ID 72345201021503994, alloc unit ID 72345201051571606 (type In-row data): Page (1:94299) could not be processed.See other errors for details.
- Msg 8939, Level 16, State 98, Line 1
- Table error: Object ID 2088535921, index ID 0, partition ID 72345201021503994, alloc unit ID 72345201051571606 (type In-row data), page (1:94299). Test (IS_OFF (BUF_IOERR, pBUF->bstat)) failed.
- CHECKDB found 0 allocation errors and 2 consistency errors in table 'yourtable' (object ID 2088535921).
- CHECKDB found 0 allocation errors and 2 consistency errors in database 'yourdb'.
- repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB (yourdb).
- ---------------------------------------------------------------------------------------------------------------------------------
現(xiàn)在我們應(yīng)該如何做?
1.通過(guò)上面的提示,告訴我們:對(duì)象 2088535921出錯(cuò),它是一個(gè)表,頁(yè)面為1:94299
2.接下來(lái),我們判斷損壞的頁(yè)在堆上還是聚集索引還是非聚集索引,sql server方法為:
- dbcc traceon (3604, -1)
- go
- dbcc page('yourdb', 1, 94299, 3)
- go
在輸出的結(jié)果里(會(huì)報(bào)錯(cuò),但可以看到頁(yè)頭信息),可以看到
- Metadata: IndexId = n
如果n是0而表示是堆,1表示是聚集索引,>1是表示非聚集索引
ps:其實(shí)從提示信息的Object ID 2088535921, index ID 0 ,也可以簡(jiǎn)單判斷是堆.
3.根據(jù)上面的第2步,我們知道這個(gè)頁(yè)面是堆,這對(duì)我們來(lái)講,不是好消息,因?yàn)槿绻?gt;1,我們可以刪除該非聚集索引,再重建索引,不會(huì)丟失數(shù)據(jù),而0或1則是元數(shù)據(jù)受損,這意味著有丟失元數(shù)據(jù)的可能性。
那么如何僅僅修復(fù)這個(gè)數(shù)據(jù)頁(yè)呢,這里我們假設(shè)該庫(kù)是full模式,并且有良好的備份策略,有全備和日志備份。
那么我們可以進(jìn)行頁(yè)面級(jí)還原操作,步驟如下:
a.首先進(jìn)行一次日志備份,如果你不放心,還可以再做一個(gè)全備;
backup log yourdb to disk='D:\DBBak\yourdb_a.trn'
b.通過(guò)完整備份來(lái)恢復(fù)該page. (yourdb.bak是一個(gè)全備。);
restore database yourdb page= '1:94299' from disk='D:\DBBak\yourdb.bak' with norecovery
c.恢復(fù)這個(gè)全備之后的差異(假設(shè)有差異yourdb.dif),如果沒(méi)有差異備,直接到d步驟;
restore database yourdb from disk='d:\DBBak\yourdb.dif'with norecovery
d.恢復(fù)之后的log備份,可能有多個(gè)(假設(shè)為yourdb_1.trn,yourdb_2.trn);
- restore log yourdb from disk='d:\DBBak\yourdb_1.trn' with norecovery
- restore log yourdb from disk='d:\DBBak\yourdb_2.trn' with norecovery
- restore log yourdb from disk='d:\DBBak\yourdb_a.trn' with norecovery
e.做一個(gè)最新的日志備;
- backup log yourdb to disk='D:\DBBak\yourdb_e.trn'
f.還原最后的(e步驟)日志備份;
- restore log yourdb from disk='d:\DBBak\yourdb_e.trn' with recovery
g.結(jié)束
4.經(jīng)過(guò)步驟三之后,我們?cè)賮?lái)檢查一下該表是否還有錯(cuò),從提示信息Object ID 2088535921里,我們查出表名tbname;
- tbname: select object_name(2088535921)
然后 dbcc checktable('yourtable')檢測(cè),如果沒(méi)有報(bào)錯(cuò),則表示修復(fù)完成
5.最后,對(duì)整個(gè)庫(kù)再做一次dbcc checkdb檢查;
ps:需要注意的是,sql server 的page級(jí)恢復(fù)在企業(yè)版和開發(fā)版中,支持聯(lián)機(jī)恢復(fù)page數(shù)據(jù),在標(biāo)準(zhǔn)版只能脫機(jī)修復(fù);
在dbcc checkdb修復(fù)選項(xiàng)里,用repair_rebuild修復(fù)數(shù)據(jù),聯(lián)機(jī)文檔稱是不丟失數(shù)據(jù),但在某些環(huán)境下可能也會(huì)丟失數(shù)據(jù),不過(guò),我沒(méi)遇到過(guò):)
用repair_allow_data_loss選項(xiàng)時(shí),聯(lián)機(jī)文檔稱可能會(huì)丟失數(shù)據(jù),而對(duì)于堆或聚集索引的頁(yè)損壞,sql server 會(huì)釋放該頁(yè)面,造成數(shù)據(jù)的丟失,但repair_allow_data_loss選項(xiàng)有兩種情況是不會(huì)丟失數(shù)據(jù),一種是非聚集索引上的頁(yè)錯(cuò)誤,另外是lob頁(yè)數(shù)據(jù)錯(cuò)誤。
數(shù)據(jù)庫(kù)頁(yè)損壞總結(jié):
一定要有良好的數(shù)據(jù)庫(kù)備份策略,備份重于一切;
要有異機(jī)備份,并且時(shí)時(shí)同步該備份文件;
當(dāng)數(shù)據(jù)庫(kù)出現(xiàn)故障時(shí),不要過(guò)于心急,冷靜分析一下錯(cuò)誤;
如果不能確定如何做,可以借助google,如果你的錯(cuò)誤信息里中文的,請(qǐng)翻譯成英文后再google,這樣搜到解決方案的可能性更大;
做修復(fù)時(shí),一定要再備一次數(shù)據(jù)庫(kù);
dbcc checkdb的repair_allow_data_loss選項(xiàng)永遠(yuǎn)是最后的選擇。
結(jié)束,如有錯(cuò)誤,請(qǐng)指正。
原文標(biāo)題:當(dāng)數(shù)據(jù)庫(kù)出現(xiàn)頁(yè)損壞或校驗(yàn)和出錯(cuò)時(shí)如何處理
鏈接:http://www.cnblogs.com/nzperfect/archive/2009/09/27/1575102.html
【編輯推薦】