- 類型:數(shù)據(jù)庫類大。3.1M語言:英文 評分:6.6
- 標簽:
在本機操作,Debug的時候,一切似乎都在掌控之中。可是提交到服務器之后,一切顯地都無比陌生。因為不熟悉SQL,準確來說就只會點Select,Update,Delete,Insert而已。昨天不小心誤刪了一張數(shù)據(jù)不多但是不在人工處理范圍內的一張表內的數(shù)據(jù)。
因為知道SQL Server是有日志這種東西的,事后我表現(xiàn)地無比淡定,在事發(fā)一個小時以內。一個小時之后,我發(fā)現(xiàn)我無法掌控這一事件了。
上網查找了恢復數(shù)據(jù)的辦法。有必要啰嗦一下。
問題1:
無論是遠程端還是服務器端,都無法對數(shù)據(jù)庫(假設數(shù)據(jù)庫叫Test)進行除‘增刪查改’的其它操作,譬如分離,脫機,還原...錯誤提示是
e.g.1 “無法分離 Test 數(shù)據(jù)庫 因為它當前正在使用!
e.g.2 “因為數(shù)據(jù)庫正在使用,未獲得對數(shù)據(jù)的排他訪問權,操作異常終止”
反正嘛,就是說你丫不能阻止別人的訪問?晌覀兙褪且@樣做的...只好跟它說拜拜了。
說拜拜的方法就是關掉所有訪問數(shù)據(jù)庫Test的進程。
createproc killspid (@dbnamevarchar(20)) as begin declare@sqlnvarchar(500) declare@spidint set@sql='declare getspid cursor for select spid from sysprocesses where dbid=db_id('''+@dbname+''')' exec(@sql) open getspid fetchnextfrom getspid into@spid while@@fetch_status<>-1 begin exec('kill '+@spid) fetchnextfrom getspid into@spid end close getspid deallocate getspid end --用法 use master exec killspid '數(shù)據(jù)庫名'
PS:
代碼我是這樣理解的,定義一段殺死訪問數(shù)據(jù)庫進程的存儲過程。寫一段獲取進程ID的代碼,循環(huán)殺死每一個進程。最后調用存儲過程。
雖然不了解存儲過程,但是意思就是這樣的吧。
問題2:
沒有備份數(shù)據(jù)庫,那該如何恢復數(shù)據(jù)呢
有個軟件叫做Log Explorer 這個東西可以根據(jù)數(shù)據(jù)庫的日志回到過去的任何一個時刻。
Log Explorer for SQL Server 打開log explorer file=>attach log file->選擇服務器和登陸方式->connect-> 選擇數(shù)據(jù)庫->attach->左面對話框中browse->view log->就可以看到log記錄了 點擊“View DDL Commands”里面就有很多drop table 命令 點擊下面的“undo”按鈕是生成表結構的語句(create table ....) 點擊下面的“Salvage”按鈕是生成插入語句的(insert into ...values....) 想恢復的話: 右鍵log記錄 undo transation->選擇保存文件名和路徑->然后打開該文件到查詢分析器里執(zhí)行 T-sql代碼就可以了 例如 如果log是delete table where ...的話,生成的文件代碼就是insert table .... log explorer使用的幾個問題 對數(shù)據(jù)庫做了完全 差異 和日志備份 備份時選用了刪除事務日志中不活動的條目 再用Log explorer打試圖看日志時 提示No log recorders found that match the filter,would you like to view unfiltered data 選擇yes,就看不到剛才的記錄了 如果不選用了刪除事務日志中不活動的條目 再用Log explorer打試圖看日志時,就能看到原來的日志
Log Explorer for SQL Server 是個好東西,但是這根本無法解決我的問題。數(shù)據(jù)庫在服務器端,學校根本不會讓我安裝一個軟件在服務器上面。而且我證實過,這個軟件必須要在服務器端裝服務器端軟件的。所以,這個對于我來說,是泡湯的。但是不代表這不是一個利器。
最后我用了一個很蛋疼的方法解決了。
1.分離數(shù)據(jù)庫,備份一個Test;
2.將數(shù)據(jù)庫附加回去,用自帶的恢復方式恢復到一個很久以前的狀態(tài);
3.將需要的那張表復制到備份的那個數(shù)據(jù)庫;
4.將備份的那個數(shù)據(jù)庫掛回去,原數(shù)據(jù)庫刪了。
這是一個很蛋疼而且碰巧那張表沒被改的方法。
頭一次知道DBA的重要性。
我的方法是一個很偶然的東西,希望大家分享一下真正能解決恢復問題的辦法。當然,每隔一段時間備份是絕對沒有錯的。
方法
另外發(fā)現(xiàn)一個比較有技術性的可行的方法
1,如果誤操作之前存在一個全庫備份(或已有多個差異備份或增量備份),首先要做的事就是進進行一次日志備份
。ㄈ绻麨榱瞬蛔屓罩疚募兇蠖胻runc. log on chkpt.選項為1那你就死翹了)
backup log dbName to disk='fileName' ----注意:是日志備份!
2,恢復一個全庫備份,注意需要使用with norecovery,如果還有其他差異或增量備份,則逐個恢復
restore database dbName from disk='fileName' with norecovery
3,恢復最后一個日志備份即剛做的日志備份,指定恢復時間點到誤操作之前的時刻
restore log dbName from disk='fileName' with stopat='date_time'
完整代碼
----1,如果誤操作之前存在一個全庫備份(或已有多個差異備份或增量備份),首先要做的事就是進進行一次日志備份(如果為了不讓日志文件變大而置trunc. log on chkpt.選項為1那你就死翹了) backup log dbName to disk='fileName' ----注意:是日志備份! ----2,恢復一個全庫備份,注意需要使用with norecovery,如果還有其他差異或增量備份,則逐個恢復 restore database dbName from disk='fileName' with norecovery ----3,恢復最后一個日志備份即剛做的日志備份,指定恢復時間點到誤操作之前的時刻 restore log dbName from disk='fileName' with stopat='date_time'