淺析數(shù)據(jù)庫頁損壞或出錯(cuò)時(shí)的處理方法
在管理數(shù)據(jù)庫時(shí)很容易出現(xiàn)問題,但是出現(xiàn)數(shù)據(jù)庫頁損壞或校驗(yàn)錯(cuò)誤時(shí)該如何解決,這也是大家需要了解的重要內(nèi)容。
最近一直在進(jìn)一步學(xué)習(xí)數(shù)據(jù)庫故障的處理方面的知識(shí),做為一個(gè)數(shù)據(jù)庫維護(hù)人員,我即期望遇到所有的數(shù)據(jù)庫出錯(cuò)的案例,以增加自己的經(jīng)驗(yàn),但同時(shí)又擔(dān)心遇到這樣或那樣無法處理的數(shù)據(jù)庫故障而導(dǎo)致數(shù)據(jù)丟失。
前幾天看到一個(gè)文章,是說一個(gè)網(wǎng)站管理員在招聘DBA時(shí),提出一個(gè)問題:“如果在SQL Server 日志里發(fā)現(xiàn)一個(gè)頁損壞或是校驗(yàn)和錯(cuò)誤應(yīng)該如何處理?”網(wǎng)站管理員描述,大概有90%的應(yīng)聘者都會(huì)采用一個(gè)方案,用DBCC CHECKDB加上其中的一個(gè)修復(fù)選項(xiàng),但其中也基本沒有人能具體解釋DBCC CHECKDB修復(fù)的過程或是工作原理及能修復(fù)到什么程度。
借助聯(lián)機(jī)文檔以及個(gè)人的一些理解和經(jīng)歷,解釋一下如何面對這個(gè)問題:"當(dāng)數(shù)據(jù)庫頁損壞或校驗(yàn)和出錯(cuò)時(shí)如何處理?"
首先,需要先了解DBCC CHECKDB,聯(lián)機(jī)文檔url:
http://technet.microsoft.com/zh-cn/library/ms176064.aspx
通過聯(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ù)(如重新生成索引);可見REPAIR_REBUILD是我們期望的。
當(dāng)你從SQL Server log里或是在程序查詢數(shù)據(jù)庫或是定期通過DBCC CHECKDB為數(shù)據(jù)庫做體檢的時(shí)候,出現(xiàn)了頁損壞或校驗(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.通過上面的提示,告訴我們:對象 2088535921出錯(cuò),它是一個(gè)表,頁面為1:94299
2.接下來,我們判斷損壞的頁在堆上還是聚集索引還是非聚集索引,sql server方法為:
- dbcc traceon (3604, -1)
- go
- dbcc page('yourdb', 1, 94299, 3)
- go
在輸出的結(jié)果里(會(huì)報(bào)錯(cuò),但可以看到頁頭信息),可以看到
- Metadata: IndexId = n
如果n是0而表示是堆,1表示是聚集索引,>1是表示非聚集索引
ps:其實(shí)從提示信息的Object ID 2088535921, index ID 0 ,也可以簡單判斷是堆.
3.根據(jù)上面的第2步,我們知道這個(gè)頁面是堆,這對我們來講,不是好消息,因?yàn)槿绻?gt;1,我們可以刪除該非聚集索引,再重建索引,不會(huì)丟失數(shù)據(jù),而0或1則是元數(shù)據(jù)受損,這意味著有丟失元數(shù)據(jù)的可能性。
那么如何僅僅修復(fù)這個(gè)數(shù)據(jù)頁呢,這里我們假設(shè)該庫是full模式,并且有良好的備份策略,有全備和日志備份。
那么我們可以進(jìn)行頁面級(jí)還原操作,步驟如下:
a.首先進(jìn)行一次日志備份,如果你不放心,還可以再做一個(gè)全備;
backup log yourdb to disk='D:\DBBak\yourdb_a.trn'
b.通過完整備份來恢復(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),如果沒有差異備,直接到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)過步驟三之后,我們再來檢查一下該表是否還有錯(cuò),從提示信息Object ID 2088535921里,我們查出表名tbname;
- tbname: select object_name(2088535921)
然后 dbcc checktable('yourtable')檢測,如果沒有報(bào)錯(cuò),則表示修復(fù)完成
5.最后,對整個(gè)庫再做一次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ù),不過,我沒遇到過:)
用repair_allow_data_loss選項(xiàng)時(shí),聯(lián)機(jī)文檔稱可能會(huì)丟失數(shù)據(jù),而對于堆或聚集索引的頁損壞,sql server 會(huì)釋放該頁面,造成數(shù)據(jù)的丟失,但repair_allow_data_loss選項(xiàng)有兩種情況是不會(huì)丟失數(shù)據(jù),一種是非聚集索引上的頁錯(cuò)誤,另外是lob頁數(shù)據(jù)錯(cuò)誤。
數(shù)據(jù)庫頁損壞總結(jié):
一定要有良好的數(shù)據(jù)庫備份策略,備份重于一切;
要有異機(jī)備份,并且時(shí)時(shí)同步該備份文件;
當(dāng)數(shù)據(jù)庫出現(xiàn)故障時(shí),不要過于心急,冷靜分析一下錯(cuò)誤;
如果不能確定如何做,可以借助google,如果你的錯(cuò)誤信息里中文的,請翻譯成英文后再google,這樣搜到解決方案的可能性更大;
做修復(fù)時(shí),一定要再備一次數(shù)據(jù)庫;
dbcc checkdb的repair_allow_data_loss選項(xiàng)永遠(yuǎn)是最后的選擇。
結(jié)束,如有錯(cuò)誤,請指正。
原文標(biāo)題:當(dāng)數(shù)據(jù)庫出現(xiàn)頁損壞或校驗(yàn)和出錯(cuò)時(shí)如何處理
鏈接:http://www.cnblogs.com/nzperfect/archive/2009/09/27/1575102.html
【編輯推薦】