SQL Server中的事務日志管理(5/9):完整恢復模式里的日志管理


當一切正常時,沒有必要特別留意什么是事務日志,它是如何工作的。你只要確保每個數據庫都有正確的備份。當出現問題時,事務日志的理解對於采取修正操作是重要的,尤其在需要緊急恢復數據庫到指定點時。這系列文章會告訴你每個DBA應該知道的具體細節。


在這篇文章里,我們會回顧下當運行在完整恢復模式時,為什么和如何進行日志備份,還有如何使用這些日志備份文件和完整數據庫備份一起,進行數據庫恢復。完整恢復模式支持數據庫數據庫還原到有效日志備份里的任何時間點,在尾日志已經備份的情況下,直到上一個提交事務的時間,在災難發生前。

什么被記錄?

在完整恢復模式里,所有操作被完整記錄。對於INSERT,UPDATE和DELETE操作,這意味着對於修改的每一行,都有日志記錄描述執行語句的事務ID,事務何時開始,何時結束,哪一頁被修改,做出的數據改變等等。

當運行在完整恢復模式時,操作會被最小化記錄,SELECT INTO,BULK INSERT和CREATE INDEX還是會完全記錄,但有完成方法有一點區別。這些操作影響的行不是各自記錄,只有數據頁被記錄,因為它們被填充。這會減少這類操作的日志負荷,但還是會保證存在需要同樣的信息來進行回滾,重做和恢復到時間點。Kalen Delaney已經發布了對於SELECT INTO索引重建操作日志插入的一些研究,包括在完整和大容量日志恢復模式。當運行在大容量日志模式里時,最小化日志操作的日志區別,會在第6篇——大容量恢復模式里的日志管理里詳細討論。

為什么備份事務日志?

在完整恢復模式里,只有日志備份會引起日志截斷。這樣的話,自上次事務日志備份起,事務日志會保存事務運行的全部和完整記錄。很多新手或業余DBA會在他們的數據庫上進行完整備份,但他們不進行事務日志備份。這樣的話,事務日志不會截斷,不停的增長增長直到用完磁盤空間,導致SQL Server停止工作。

一旦日志備份發生,日志截斷就會發生,例如自上一個備份后,且沒有其他因素(例如數據備份或還原操作)延遲截斷,有個檢查點已發生。對於會延遲可恢復VLFs截斷的完整列表,同樣保持否則不需要的活動日志的大片,例如淘氣的,長時間運行不提交的事務或數據庫鏡像或復制過程,點擊查看可能引起日志截斷的因素

事務日志的復制備份

事務日志的復制備份不會截斷事務日志。日志復制備份“單獨”存在於普通日志備份計划里,它不會中斷日志備份鏈。

簡單來說,進行事務日志備份有2個目的:可以恢復或還原到先前一個時間點,還有控制事務日志的大小。最常見事務相關引起的問題是運行在完整恢復模式里,絕不做日志備份,或進行日志備份的頻率不夠控制事務日志文件的大小。

如果你不確定是否要對一個數據庫進行事務日志備份,你可以簡單查詢下MSDB數據庫里的backupset表,使用如下的查詢:

1 SE msdb ;
2 SELECT   backup_set_id ,
3          backup_start_date ,
4          backup_finish_date ,
5          backup_size ,
6          recovery_model ,
7          [type]
8 FROM     dbo.backupset
9 WHERE    database_name = 'TestDB'

(代碼5.1:日志備份發生了么?)

在type列里,D代表數據庫備份,L代表日志備份,I代表差異備份。

注意因為backupset表里的數據不會受備份和還原行為影響,你可以從另外一個查詢來驗證你的發現,通過查詢sys.database_recovery_status看下last_log_backup_lsn的值,或者查詢sys.databases表看下log_reuse_wait_desc的值(如果備份需要的話會返回LOG_BACKUP)。

如何備份事務日志?

我們已經提過,如果不首先進行至少一次完整備份是不能進行日志備份的。事實上,你的數據庫要運行在完整恢復模式,但從未備份過的話,它不是運行在完整恢復模式里的。數據庫會是在自動截斷模式里直到第一次完整備份完成。

數據庫備份,完整,日志或者其他方面的,使用BACKUP命令進行備份。這個命令接受很多選項,它的文檔在這里:https://msdn.microsoft.com/zh-cn/library/ms186865.aspx 。但是,它最基本的,進行完整備份到磁盤的命令如下:

1 BACKUP DATABASE DatabaseNameTO DISK ='FileLocation\DatabaseName.bak';

如果這是第一個進行的備份,DatabaseName.bak會在指定目錄里創建。如果已經存在這樣的文件,默認會在那個文件增加一個序號。為了避免這個行為,保證任何已存的文件被覆蓋,我們可以使用如下的INIT選項:

1 BACKUP DATABASE DatabaseNameTO DISK ='FileLocation\DatabaseName.bak'WITH INIT;

通常,每個連續的備份會有一個唯一的名稱;在下個部分,恢復到災難點會有詳細介紹。

在每個定期(例如每天)完整備份后,會有頻繁(每小時)的日志備份,這個的基本命令非常簡單:

1 BACKUP LOG DatabaseNameTO DISK ='FileLocation\DatabaseName_Log.bak';

存儲日志備份

很明顯,數據和日志文件備份不應該和服務器存儲在同個硬盤。如果那個硬盤硬件失敗的話,你的所有備份會和原數據文件一起丟失,備份就沒用了。文件應該備份到獨立的設備,或備份到本地另一個硬盤或網絡映射硬盤。

日志備份頻率

在以前的文章提過,你會在每15分鍾備份一次日志,甚至更高頻率。這樣的話,為了避免恢復大量事務日志的需要,你會選擇包含有差異備份、事務日志備份穿插的完整備份計划。

實際上,備份計划經常會在理想和現實之間妥協,即在真正丟失數據的風險和公司涉及緩解磁盤花費之間。很多非常重要的業務程序使用稍微簡單,但嚴謹的備份計划,可能涉及每晚定期的完整備份和每小時的日志備份。

日志備份的頻率也會由數據庫提交的日志數決定。對於非常忙碌的數據庫,頻繁備份來控制日志大小是很有必要的。

計算日志備份的頻率是沒有簡單的方法。大多數DBA會采用對於日志應該備份頻率的最佳估計,然后觀察文件的增長情況,需要的話再調整備份計划來阻止過度增長。

日志鏈和如何中斷它

已經提過,沒有第一次至少一次的完整備份是不能進行事務日志備份的。為了恢復數據庫到某個時間點,要么到特定日志備份的結尾或特定日志的某個時間點,必須要有完整不截斷的日志記錄鏈,從在完整(或差異備份)后的第一個日志備份,剛好一直到災難時間點。這被稱為日志鏈(log chain)

有很多方法中斷日志鏈,如果你有意這樣做,你只能恢復數據庫到日志中斷事件前進行的日志備份的時間點。簡單來說,如果你在意恢復你數據的能力,中斷日志鏈不是個好方法。最常見的中斷日志鏈的2個方法包括:

  • 事務日志備份文件丟失或損壞——你只能恢復到上一次正確的日志備份。日志鏈會在下一個正確的完整或差異備份開始。
  • 切換到簡單恢復模式——如果你從完整切換到簡單恢復模式,這回中斷日志鏈,因為檢查點被觸發,事務日志會立即截斷。當你切換回完整模式,你要進行另一個完整備份來重啟日志鏈。事實上,在你進行完整備份前,數據庫還是自動截斷模式,你不能備份日志文件。

在SQL Server 2008以前,有2個命令,叫做BACKUP LOG WITH NO_LOG和BACKUP LOG WITH TRUNCATE_ONLY(功能是一樣的),當被執行時,會強制日志文件截斷來中斷日志鏈。你不應該在任何版本的SQL Server里執行這些命令,但我這里提起它們是因為當處理“失控的日志文件“時,沒有理解它們會影響數據庫的恢復,它們會被不小心使用。我們會在第8篇——救命,我的日志滿了里詳細討論。

尾日志備份

只要你有最近的一個完整備份和一個完整的日志鏈,你可以恢復你的數據庫到任何災難前,存在的最后日志備份的狀態。但是,假設你進行的是每小時備份一次事務日志,整點備份,當災難發生在下午1:45。你會丟失45分鍾的數據;當然,如果災難太毀滅性,備份的事務日志不能挽回,那你會丟失大量的數據。

但是,有時備份的日志還是可用的,即使數據文件已損壞,如果事務文件在獨立、專門的硬盤上。如果是這樣的話,你應該備份現在的事務日志,例如進行自上次日志備份后,生成日志記錄的最后備份。這會捕獲當前日志文件里剩余日志記錄,直到災難點。這稱為尾日志備份(tail log backup),是開始恢復和還原操作前的最后應該做的操作。

尾日志備份和最小化日志操作

如果由於數據庫災難,數據文件不可用,日志尾包含最小化日志操作,那是可以進行尾日志備份,因為這需要訪問在數據文件里擴展的數據修改。這在第6篇——大容量日志模式里的日志管理里會詳談。

如果你想恢復的數據庫是在線的,那尾日志備份如下:

1 BACKUP LOG DatabaseNameTO DISK ='FileLocation\DatabaseName_Log.bak'WITH NORECOVERY

NORECOVERY選項把數據庫放入恢復狀態並假設你下一個操作是還原。如果數據庫是離線就不會開始,你還是應該嘗試如剛介紹的尾日志備份(盡管NOCOVERY選項可以忽略,因為沒有處理中的事務)。

如果你確認日式文件已損壞,微軟文檔建議,作為最后的方法,你用下列方法嘗試進行尾日志備份:

1 BACKUP LOG DatabaseNameTO DISK ='FileLocation\DatabaseName_Log.bak'WITH CONTINUE_AFTER_ERROR

如果master數據庫和數據文件已損壞,但是日志還是可用的,微軟建議重建master數據庫然后備份最后活動日志。但這些話題已經在這個系列文章的話題之外,我給你個文檔做進一步的參考:https://msdn.microsoft.com/zh-cn/library/ms190952.aspx

進行恢復和還原

進行完尾日志備份,如果可能的話,下一步是恢復最后一次完整備份(隨后是差異備份,如果需要的話),然后恢復所有一系列的備份日志文件,包括尾日志備份。對這一一系列恢復操作的基本語法如下:

1 RESTORE {DATABASE | LOG} DatabaseNameFROM DISK ='FileLocation\FileName.bak'WITH NORECOVERY;

當你恢復時如果你忽略WITH NORECOVERY選項,那么默認RESTORE命令會用WITH RECOVERY命令繼續。換句話說,SQL Server會嘗試數據和日志文件的一致,前滾完成的事務,然后回滾未完成的事務如果需要的話。通過指定WITH NORECOVERY,我們命令SQL Server我們進入一個還原步驟,在我們進行任何回滾前,很多操作需要前滾。在還原步驟里,恢復最后一次備份后,數據庫可以如下進行恢復:

1 RESTORE DATABASE DatabaseName WITH RECOVERY

通常需要把數據庫恢復到一個不同的位置,這樣在恢復過程中你可以移動文件,如這里所介紹的:https://msdn.microsoft.com/zh-cn/library/ms190255.aspx

數據庫崩潰后恢復

下面例子介紹如何對災難數據庫恢復的響應,數據文件已經不能訪問。

完整恢復到失敗點

假設由硬件導致數據庫災難后,當前日志還可以訪問,那么理論上是可以把你的數據庫恢復到災難前的時間點,使用下列步驟:

  1. 備份尾日志
  2. 恢復最近的完整備份(加上差異備份,如何合適的話)
  3. 逐個恢復完整(或差異)備份后的每個事務日志備份,直到災難前
  4. 恢復尾日志備份
  5. 恢復數據庫上線

在線幫助可以找到很多從一個備份集恢復和還原演示的例子,換句話說是備份和還原在一個”設備“。實際上,這表示當備份到磁盤時,備份設備是那個磁盤上的某個.bak文件。

因此,例如下面代碼展示的是使用包含一個備份文件和一個事務日志備份的備份,如何進行完整恢復。為了執行這個代碼,首先你需要定位到TestDB數據庫,再插入幾條數據(方便起見,用腳本來做。)。你還需要在你的數據庫服務器的本地C盤上創建”Backup“目錄,或者修改到合適的文件路徑。

 1 -- Perform a full backup of the Test database
 2 -- The WITH FORMAT option starts a new backup set
 3 -- Be careful, as it will overwrite any existing sets
 4 -- The full backup becomes the first file in the set
 5 BACKUP DATABASE TestDB
 6 TO DISK = 'C:\Backups\TestDB.bak'
 7 WITH FORMAT;
 8 GO
 9 
10 -- Perform a transaction log backup of the Test database
11 -- This is the second file in the set
12 BACKUP Log TestDB
13 TO DISK = 'C:\Backups\TestDB.bak'
14 GO
15 
16 -- ....<FAILURE OCCURS HERE>....
17 
18 -- The RESTORE HEADERONLY command is optional.
19 -- It simply confirms the files that comprise 
20 -- the current set
21 RESTORE HEADERONLY
22 FROM DISK = 'C:\Backups\TestDB.bak'
23 GO
24 
25 -- Back up the tail of the log to prepare for restore
26 -- This will become the third file of the bakup set
27 BACKUP Log TestDB
28 TO DISK = 'C:\Backups\TestDB.bak'
29 WITH NORECOVERY;
30 GO
31 
32 -- Restore the full backup
33 RESTORE DATABASE TestDB
34 FROM DISK = 'C:\Backups\TestDB.bak'
35 WITH FILE=1, NORECOVERY;
36 
37 -- Apply the transaction log backup
38 RESTORE LOG TestDB
39 FROM DISK = 'C:\Backups\TestDB.bak'
40 WITH FILE=2, NORECOVERY;
41 
42 -- Apply the tail log backup
43 RESTORE LOG TestDB
44 FROM DISK = 'C:\Backups\TestDB.bak'
45 WITH FILE=3, NORECOVERY;
46 
47 -- Recover the database
48 RESTORE DATABASE TestDB
49 WITH RECOVERY;
50 GO

(代碼5.2:備份到,從備份集恢復,不推薦。)

但是,使用備份集看起來是數據庫備份到磁帶時留下的遺物。當備份到磁盤時,使用這個計划是個不好的想法,顯然,備份文件會增長非常迅速。

實際上,常見的是每個完整備份和事務日志備份文件的每個文件名都不一樣,都標記上備份發生的日期和時間。例如,大多數第三方備份工具,流行社區生成的腳本,加上SSMS里的維護計划向導/設計器,都會創建各個日期標記的文件,例如WIN8X64_AdventureWorks2008R2_FULL_20151025_120003.bak。

這樣的話,更常見的備份和還原計划會使用唯一命名的備份,如下所示:

 1 USE master;
 2 BACKUP DATABASE TestDB
 3 TO DISK ='C:\Backups\TestDB.bak'
 4 WITH INIT;
 5 GO
 6 
 7 -- Perform a transaction log backup of the Test database
 8 BACKUP Log TestDB
 9 TO DISK ='C:\Backups\TestDB_log.bak'
10 WITH INIT;
11 GO
12 
13 -- ....<FAILURE OCCURS HERE>....
14 
15 -- Back up the tail of the log to prepare for restore
16 BACKUP Log TestDB
17 TO DISK ='C:\Backups\TestDB_taillog.bak'
18 WITH NORECOVERY, INIT;
19 GO
20 
21 -- Restore the full backup
22 RESTORE DATABASE TestDB
23 FROM DISK = 'C:\Backups\TestDB.bak'
24 WITH NORECOVERY;
25 
26 -- Apply the transaction log backup
27 RESTORE LOG TestDB
28 FROM DISK = 'C:\Backups\TestDB_log.bak'
29 WITH NORECOVERY;
30 
31 -- Apply the tail log backup
32 RESTORE LOG TestDB
33 FROM DISK = 'C:\Backups\TestDB_taillog.bak'
34 WITH NORECOVERY;
35 
36 -- Recover the database
37 RESTORE DATABASE TestDB
38 WITH RECOVERY;
39 GO

(代碼5.3:備份到,從唯一命名備份文件集還原)

恢復到上次正確日志備份的時間點

有時候很遺憾,不能進行完整恢復:例如由於災難當前事務日志不可用。這樣的話,我們會需要還原數據庫導最近日志備份的末尾。我們要為這個可能做好准備,例如損壞的硬盤包含事務日志,這就決定了事務日志備份的頻率。如果每15分鍾備份一次,那么你就有丟失15分鍾數據的風險。

假設我們已經進行了如下的一系列備份。為了演示需要,我們覆蓋了先前的備份文件,實際的備份文件集明顯比這個更短。

 1 -- FULL BACKUP at 2AM
 2 USE master ;
 3 BACKUP DATABASE TestDB
 4 TO DISK = 'C:\Backups\TestDB.bak'
 5 WITH INIT ;
 6 GO
 7 
 8 -- LOG BACKUP 1 at 2.15 AM
 9 USE master ;
10 BACKUP LOG TestDB
11 TO DISK = 'C:\Backups\TestDB_log.bak'
12 WITH INIT ;
13 GO
14 
15 -- LOG BACKUP 2 at 2.30 AM
16 USE master ;
17 BACKUP LOG TestDB
18 TO DISK = 'C:\Backups\TestDB_log2.bak'
19 WITH INIT ;
20 GO

(代碼5.4:一個簡短序列的日志備份)

如果災難性故障發生在上午2:30,我們將需要恢復數據庫到上午2:30的尾日志備份狀態。

在這個例子的恢復步驟和我們在代碼5.3里看到的非常類似,但因為不能進行尾日志備份,我們只能恢復到特定點,我們要使用代碼5.5里所顯示的STOPAT選項。

 1 --RESTORE Full backup
 2 RESTORE DATABASE TestDB
 3 FROM DISK = 'C:\Backups\TestDB.bak'
 4 WITH NORECOVERY;
 5 
 6 --RESTORE Log file 1
 7 RESTORE LOG TestDB
 8 FROM DISK = 'C:\Backups\TestDB_log.bak'
 9 WITH NORECOVERY, STOPAT = 'Jan 01, 2020 12:00 AM';
10 
11 --RESTORE Log file 2
12 RESTORE LOG TestDB
13 FROM DISK = 'C:\Backups\TestDB_Log2.bak'
14 WITH NORECOVERY, STOPAT = 'Jan 01, 2020 12:00 AM';
15 
16 --Recover the database
17 RESTORE DATABASE TestDB
18 WITH RECOVERY;
19 GO

(代碼5.5:使用STOPAT恢復到時間點)

因為我們在將來指定了STOPAT選項,這個代碼會前滾所有完成的事務到第2個事務日志的結尾。

或者我們可以在特定日志文件里事務記錄的時間范圍里指定時間。這樣的話,數據庫會恢復到指定時間的最后一次提交的事務。當你知道你想恢復的時間點,卻不知道那個時間包含哪些日志備份時,這個非常重要。

還有可能恢復到指定標記的事務。這是很有用的,例如,你要恢復被特定程序訪問多個數據庫,到邏輯一致的時間點。這個話題在這里不會詳細討論,你可以參看下微軟的在線幫助(https://msdn.microsoft.com/zh-cn/library/ms187014.aspx),另外Mladen Prajdic也提供了一個很好的例子:http://weblogs.sqlteam.com/mladenp/archive/2010/10/20/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx

“錯誤事務”后恢復

在任何數據庫故障上下文之外,還有必要恢復數據庫備份,加上事務日志,為了回到數據庫的指定時間點,在錯誤的數據修改之前,例如刪除表或清空表。

對此情況你的響應取決於問題本身。如果可能的話,你可能從數據庫中斷所有用戶的連接(在通知它們后),評估下所發生的影響。在某些情況下,你需要估計下問題發生的時間,然后進行數據庫完整恢復,恢復到日志使用的時間點。一旦恢復完成,你必須通知用戶有些事務可能已經丟失,請求諒解。

當然,你不能經常在這個方式里中斷正常業務操作來修正一個突發的數據丟失。因為現在的數據庫還是在線,在運行,在被用戶訪問,你只能在STANDBY模式里嘗試恢復數據庫備份。這允許進一步的日志備份恢復,不像使用NORECOVERY,數據庫還是可以訪問的。恢復計划會如下:

  1. 在STANDBY模式里恢復數據庫備份,在當前數據庫旁(新建一個數據庫)。
  2. 回滾記錄到在錯誤事務發生,數據丟失前的時間點。
  3. 拷貝丟失的數據到當前數據庫並刪除恢復副本(新建的數據庫)。

當然,這個過程並不簡單,它會非常耗時。除非你購買了特定的日志讀取工具,可以直接訪問日志備份,前滾日志意味着一系列涉及到日志恢復,檢查數據,進一步還原等等痛苦步驟,直到找出具體發生錯誤日志的位置。第3步也會非常困難,因為你在當前實時的系統里引入數據,要和當前數據庫狀態必須一致,因此會有一致性的問題。

我們來看下上述第1步和第2步實現的例子。

首先我們通過下列腳本重新創建TestDB數據庫,在新的LogTest表里插入10條測試記錄。

 1 USE master
 2 GO
 3 
 4 IF EXISTS ( SELECT  name
 5             FROM    sys.databases
 6             WHERE   name = 'TestDB' ) 
 7     DROP DATABASE TestDB ;
 8 
 9 CREATE DATABASE TestDB ON
10 (
11   NAME = TestDB_dat,
12   FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\TestDB.mdf'
13 ) LOG ON
14 (
15   NAME = TestDB_log,
16   FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\TestDB.ldf'
17 ) ;
18 
19 USE TestDB
20 GO
21 IF OBJECT_ID('dbo.LogTest', 'U') IS NOT NULL 
22     DROP TABLE dbo.LogTest ;
23 SELECT TOP 10
24   SomeID = IDENTITY( INT,1,1 ),
25   SomeInt = ABS(CHECKSUM(NEWID())) % 50000 + 1 ,
26   SomeLetters2 = CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65)
27   + CHAR(ABS(CHECKSUM(NEWID())) % 26 + 65)
28 INTO    dbo.LogTest
29 FROM    sys.all_columns ac1
30         CROSS JOIN sys.all_columns ac2 ;
31 GO
32 USE master
33 GO

在代碼5.6里,我們直接進行一個完整數據庫備份(覆蓋先前的任何備份文件)。你需要創建“Backups”目錄,如果你已經做了,或者調整到合適目錄。

1 -- full backup of the database
2 BACKUP DATABASE TestDB
3 TO DISK ='C:\Backups\TestDB.bak'
4 WITH INIT;
5 GO

(代碼5.6:TestDb的完整備份)

然后我們插入一條新紀錄到LogTest表。

 1 USE TestDB
 2 GO
 3 INSERT INTO [TestDB].[dbo].[LogTest]
 4            ([SomeInt]
 5            ,[SomeLetters2])
 6      VALUES
 7            (66666,
 8            'ST')
 9            
10 SELECT * FROM dbo.LogTest

(代碼5.7:插入TestDB第11行)

現在我們當前TestDB數據庫的LogTest表有11條記錄,備份版本里有10條記錄。現在我們在日志備份里捕獲額外的修改,如代碼5.8所示:

1 USE master
2 GO
3 BACKUP Log TestDB
4 TO DISK ='C:\Backups\TestDB_log.bak'
5 WITH INIT;
6 GO

(代碼5.8:TestDB的日志備份)

現在,我們來模擬一個錯誤的“壞事務”,直接刪除LogTest表,之后我們進行最后日志備份。

 1 USE TestDB
 2 GO
 3 DROP TABLE dbo.LogTest ;
 4 
 5 USE master
 6 GO
 7 BACKUP Log TestDB
 8 TO DISK ='C:\Backups\TestDB_log2.bak'
 9 WITH INIT;
10 GO

(代碼5.9:災難發生!)

為了嘗試找回丟失的數據,不中斷正常業務操作,我們來還原一個在STANDBY模式里TestDB數據庫的副本。Standby模式數據庫的數據和日志叫做ANewTestDB,移動到”Standby“目錄(你要事先創建這個目錄)。

 1 -- restore a copy of the TestDB database, called
 2 -- ANewTestDB, in STANDBY mode
 3 USE master ;
 4 GO
 5 RESTORE DATABASE ANewTestDB
 6    FROM DISK ='C:\Backups\TestDB.bak'
 7    WITH STANDBY='C:\Backups\ANEWTestDB.bak',
 8    MOVE 'TestDB_dat' TO 'C:\Standby\ANewTestDB.mdf', 
 9    MOVE 'TestDB_log' TO 'C:\Standby\ANewTestDB.ldf'
10 GO

(代碼5.10:在STANDBY模式里恢復TestDB副本)

現在我們有一個名為ANewTestDB的數據庫,它在”備用/只讀“模式里,如下所示:

 (圖5.1:待命數據庫)

對ANewTestDB數據庫的Lost表查詢會返回10條記錄。但是我們想把表恢復到在刪除之前的狀態。因此,下一步進行對待命數據庫進行日志備份還原。

1 USE master
2 GO
3 RESTORE LOG ANewTestDB
4 FROM DISK = 'C:\Backups\TestDB_log.bak'
5    WITH STANDBY='C:\Backups\ANewTestDB_log.bak'

(代碼5.11:在待命模式里的ANewTestDB數據庫里,恢復日志備份)

這個時候,ANewTestDB數據庫已經恢復11條記錄,我們可以拷貝這些記錄到TestDB數據庫。如果我們進一步,還原第2個日志備份,我們會發現我們走過頭了,LogTest表同樣在待命數據庫里丟失了。

其他進行待命還原是考慮使用例如Red Gate的SQL Virtual Restore的第三方工具,它提供多個數據庫備份文件直接還原,數據庫正常運行,不需要物理還原的方法。

不管DBA是否喜歡,開發者經常訪問生產數據庫進行即席數據讀取和修改。保持這些操作正常進行是DBA和開發者的連帶責任,因此不要引起剛才介紹這類操作的問題。我們會在第6篇——處理大容量操作里繼續討論這個話題。

當然,修復行動的本身需要取決於錯誤事務的本身。如果表被”不小心刪除“,那你可以進行RESTORE WITH STANDBY方法。其他時間,你可以直接創建腳本來反向這些流氓修改。

如果損壞只影響到單列或少量行,那么可以使用SQL Data Compare這樣的工具,可以直接和備份文件比較,可以進行級別的還原。

另外,如果你使用SQL Server 2005(或更高)的企業版本,我們有最近數據庫快照功能,你可以執行快照查詢來取回數據庫執行快照時的數據,然后寫UPDATE或INSERT命令把快照里是數據寫入當前運行的數據庫。

最后,作為最后一招,專門的日志讀取工作會幫你逆向事務的影響,盡管我不知道在SQL Server 2005和后續版本里的運行的任何可靠性。

小結

在這篇文章里,我們討論了在完整恢復模式里,備份的基本和對數據庫日志文件恢復,這些都是生產數據庫的常規操作。

對大多數DBA,進行時間點恢復是很少的,但它是這些工作之一,如果需要的話,做且做好它是絕對必要的;DBA的名聲取決於它。

在災難情況里,硬盤故障等等,會涉及時間點的恢復,如果你幸運的話,可以做尾日志的備份,那你可以恢復到災難前的時間點。如果事務日志不可用,或者你為了恢復到逆向”錯誤事務“發生前的時間點,那么情況變得棘手,希望這篇文章里這一步談到的一些技術可以幫到你。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM