SQL Server 2008以上誤操作數(shù)據(jù)庫(kù)恢復(fù)方法——日志尾部備份
掃描二維碼
隨時(shí)隨地手機(jī)看文章
問(wèn)題:
? ? ? ? ?經(jīng)常看到有人誤刪數(shù)據(jù),或者誤操作,特別是update和delete的時(shí)候沒(méi)有加where,然后就喊爹喊娘了。人非圣賢孰能無(wú)過(guò),做錯(cuò)可以理解,但不能縱容,這個(gè)以后再說(shuō),現(xiàn)在先來(lái)解決問(wèn)題。
? ? ? ? 遇到這種情況,一般都是沒(méi)有做備份,不然也不會(huì)來(lái)發(fā)問(wèn)了。首先要冷靜,否則會(huì)有更大的災(zāi)難。直到你放棄。
解決方法:
? ? ? ?對(duì)于這類問(wèn)題,主要是找回誤操作之前的數(shù)據(jù),在2008之前,有個(gè)很出名的工具Log Exploer,聽說(shuō)還挺好用的,這個(gè)網(wǎng)上大把教程,這里就不多說(shuō)了。但是唯一遺憾的是,不支持2008及更高版本,這時(shí)除了其他第三方工具,那么最常用的就是本文提到的方法——日志尾部備份。本文實(shí)驗(yàn)環(huán)境2008R2,對(duì)于2008及其以上版本可以使用這個(gè)方法,其實(shí)2005也可以,2000很少用,沒(méi)試過(guò),只是2008之前可以使用Log Exploer,所以就沒(méi)必要用這種方法。
? ? ? 下面圖文并茂講解操作方法,至于原理,不屬于本文范圍,而且我相信真遇到誤操作的時(shí)候,估計(jì)沒(méi)人會(huì)看原理了。
步驟:
(1)、檢查數(shù)據(jù)庫(kù)的恢復(fù)模式,如圖:
或者使用腳本檢查:
[sql]?view
plain?copy
SELECT?recovery_model,recovery_model_desc??
FROM?sys.databases??
WHERE?name?='AdventureWorks'??
結(jié)果如下:
? ? ? ? 確保數(shù)據(jù)庫(kù)的恢復(fù)模式最起碼不能為【簡(jiǎn)單】。至于如何修改成完整模式,我覺得這些應(yīng)該沒(méi)必要多說(shuō)了。
?
? ? ? ?切記,對(duì)于任何重要環(huán)境,不僅僅是客戶正式環(huán)境(俗稱生產(chǎn)環(huán)境),都強(qiáng)烈建議使用【完整恢復(fù)模式】,雖然對(duì)于另外兩種(大容量日志(BULK_LOGGED)、簡(jiǎn)單(SIMPLE))來(lái)說(shuō),完整恢復(fù)模式產(chǎn)生的日志會(huì)大,但是在出現(xiàn)問(wèn)題的時(shí)候,就會(huì)覺得這些都不算什么了。并且我也想不到任何理由對(duì)于正式環(huán)境不使用完整恢復(fù)模式。只要管理得當(dāng),完整恢復(fù)模式的日志也不會(huì)太變態(tài)。
?
(2)、這里其實(shí)隱含另外一步,曾經(jīng)做過(guò)最少一次的完整備份。因?yàn)樗蓄愋偷膫浞荻蓟谕暾麄浞?,如果沒(méi)有最少一次完整備份,其他類型的備份都是多余的,所以在這里強(qiáng)調(diào)一下,在創(chuàng)建完一個(gè)新數(shù)據(jù)庫(kù)之后,強(qiáng)烈建議甚至強(qiáng)制做一次完整備份。
[sql]?view
plain?copy
SELECT??database_name,recovery_model,name???
FROM?msdb.dbo.backupset??
使用上面的語(yǔ)句粗略可以看到有那些數(shù)據(jù)庫(kù)做過(guò)備份,由于測(cè)試,所以做了幾次備份,可以看到我這個(gè)時(shí)間點(diǎn)已經(jīng)做了備份了。
(3)、確保別人不再連接數(shù)據(jù)庫(kù),然后做一次日志尾部備份:
首先先創(chuàng)建一點(diǎn)數(shù)據(jù):
[sql]?view plain?copy /*?? 由于tempdb永遠(yuǎn)為簡(jiǎn)單恢復(fù)模式,所以不適合做案例。?? 這里使用微軟的示例數(shù)據(jù)庫(kù)AdventureWorks?? */?? USE?AdventureWorks?? GO?? IF?OBJECT_ID('testRestore')?IS?NOT?NULL??? ????DROP?TABLE?testRestore?? GO?? CREATE?TABLE?testRestore?? ????(?? ??????id?INT?IDENTITY(1,?1)?,?? ??????NAME?VARCHAR(50)?? ????);?? --插入測(cè)試數(shù)據(jù):????? INSERT?INTO?testRestore(Name)?? SELECT?'test1'?? UNION?ALL??? SELECT?'test2'?? UNION?ALL??? SELECT?'test3'?? UNION?ALL??? SELECT?'test4'?? UNION?ALL??? SELECT?'test5'?? UNION?ALL??? SELECT?'test6'?? UNION?ALL??? SELECT?'test7'?? UNION?ALL??? SELECT?'test8'?? SELECT?*?FROM?testRestore?? 檢查一下結(jié)果:
然后來(lái)做個(gè)刪除操作,為了定位是啥時(shí)候發(fā)生的,我加了一個(gè)waitfor命令,讓它在某個(gè)時(shí)間發(fā)生,這樣恢復(fù)的時(shí)候就有準(zhǔn)確性:
[sql]?view
plain?copy
USE?AdventureWorks??
GO??
WAITFOR?TIME?'21:45'??
DELETE?FROM?dbo.testRestore??
現(xiàn)在來(lái)看看數(shù)據(jù):
[sql]?view
plain?copy
USE?AdventureWorks??
GO??
SELECT?*?FROM?dbo.testRestore??
到這一步,災(zāi)難出現(xiàn)了。但是切記要冷靜。
下面就是本文的重點(diǎn)開始,做一次日志備份,最重要是選擇【備份日志尾部】
然后在【選項(xiàng)】頁(yè)選擇:除【事務(wù)日志】除,其他紅框包裹的地方為強(qiáng)烈建議勾選的地方。并且保證數(shù)據(jù)庫(kù)不要有別人在連接,因?yàn)閭浞萑罩疚膊繒?huì)使數(shù)據(jù)庫(kù)處于還原狀態(tài),拒絕其他會(huì)話的連接,如果不斷開其他連接,是備份不了的。
然后按確定,當(dāng)然,可以使用上方的【腳本】來(lái)生成語(yǔ)句:
[sql]?view
plain?copy
USE?Master??
GO??
BACKUP?LOG?[AdventureWorks]?TO??DISK?=?N'E:AdventureWorks.bak'?WITH??NO_TRUNCATE?,?NOFORMAT,?NOINIT,??NAME?=?N'AdventureWorks-事務(wù)日志?備份',?SKIP,?NOREWIND,?NOUNLOAD,??NORECOVERY?,?COMPRESSION,??STATS?=?10,?CHECKSUM??
GO??
declare?@backupSetId?as?int??
select?@backupSetId?=?position?from?msdb..backupset?where?database_name=N'AdventureWorks'?and?backup_set_id=(select?max(backup_set_id)?from?msdb..backupset?where?database_name=N'AdventureWorks'?)??
if?@backupSetId?is?null?begin?raiserror(N'驗(yàn)證失敗。找不到數(shù)據(jù)庫(kù)“AdventureWorks”的備份信息。',?16,?1)?end??
RESTORE?VERIFYONLY?FROM??DISK?=?N'E:AdventureWorks.bak'?WITH??FILE?=?@backupSetId,??NOUNLOAD,??NOREWIND??
GO??
此時(shí),數(shù)據(jù)庫(kù)會(huì)處于【正在還原】的狀態(tài)
如果發(fā)現(xiàn)備份不了可以用下面語(yǔ)句查看,并把spid殺掉:
[sql]?view
plain?copy
SELECT??*?FROM?sys.sysprocesses?WHERE?dbid=DB_ID('AdventureWorks')??
執(zhí)行結(jié)果:
然后kill掉。
接著繼續(xù)備份。
?
然后進(jìn)行還原,如圖:
先要還原完整備份,選擇最近的那次,由于日志備份的特性(以后其他文章再說(shuō)),只認(rèn)最后一次備份,所以要選擇最新的那次,否則還原不了。
這里又有一個(gè)注意事項(xiàng),記得選擇:
接著還原日志文件,這是最最重要的一步:
然后:
由于實(shí)驗(yàn)的時(shí)候出了點(diǎn)問(wèn)題,后面重做了,所以時(shí)間選擇到22:19分,我是在22:20分刪除數(shù)據(jù)的。這里不用太在意,只要把時(shí)間點(diǎn)指定到你誤刪除的時(shí)間之前即可。而由于日志尾部備份都是最后一個(gè)備份文件,所以這里選則紅框部分即可:
現(xiàn)在再檢查一下:
可以看到,數(shù)據(jù)已經(jīng)還原成功。
?
總結(jié):
平時(shí)不做備份,出問(wèn)題來(lái)喊急,這是茍有自取,還有一些腦袋發(fā)熱的人喜歡看到ldf很大就直接刪除,那以后出問(wèn)題就別怪微軟了。
本文中的方法看上去有點(diǎn)繁瑣,但是實(shí)操幾次就覺得好了,但是步驟建議嚴(yán)格按照上面說(shuō)的,因?yàn)橐坏┎僮麇e(cuò)誤,就很麻煩,此時(shí)再次強(qiáng)調(diào)——冷靜冷靜再冷靜?。。。。?!
這種方法有幾個(gè)缺點(diǎn):
1、?????????????如果你發(fā)現(xiàn)誤操作以后還有很多人做了操作,那么你還原成功后,別人的操作就會(huì)沖掉,所以發(fā)生誤操作后,要馬上停止別人對(duì)數(shù)據(jù)庫(kù)的操作。
2、?????????????這個(gè)方法要對(duì)數(shù)據(jù)庫(kù)獨(dú)占,所以你想偷偷恢復(fù)是不行的了。勇敢承認(rèn)錯(cuò)誤吧。
對(duì)于核心數(shù)據(jù)表,還是要先做好預(yù)防操作,可以看:SQLServer恢復(fù)表級(jí)數(shù)據(jù)。