1. 備份與還原的基礎說明 我們知道在DBA的日常工作中,SQL Server 資料庫的恢復請求偶有發生,可能是用作數據的追蹤,可也可能能是資料庫的災難恢復。 資料庫常用的備份命令如下: 備份文件的命名格式為:資料庫名字_備份類型(Full或Diff或Trn的一種)_時間格式.文件類型(bak或tr ...
1. 備份與還原的基礎說明
我們知道在DBA的日常工作中,SQL Server 資料庫的恢復請求偶有發生,可能是用作數據的追蹤,可也可能能是資料庫的災難恢復。
資料庫常用的備份命令如下:
----完整備份 Declare @FullFileName Varchar(200) Declare @FileFlag varchar(20) Set @FileFlag=REPLACE(CONVERT(VARCHAR(10), GETDATE(), 120), '-','')+ REPLACE(CONVERT(VARCHAR(10), GETDATE(), 8), ':', '') Set @FullFileName='文檔路徑\資料庫名字_FULL'+@FileFlag+'.bak' BackUp DataBase 資料庫名字 To Disk=@FullFileName with init ----差異備份 Declare @DiffFileName varchar(200) Declare @FileFlag varchar(200) Set @FileFlag=REPLACE(CONVERT(VARCHAR(10), GETDATE(), 120), '-','')+ REPLACE(CONVERT(VARCHAR(10), GETDATE(), 8), ':', '') Set @DiffFileName='文檔路徑\資料庫名字_Diff_'+@FileFlag+'.bak' BackUp DataBase 資料庫名字 To Disk=@DiffFileName with init,differential ----事務日誌備份 Declare @FileName Varchar(200) Declare @FileFlag varchar(20) Set @FileFlag=REPLACE(CONVERT(VARCHAR(10), GETDATE(), 120), '-','')+ REPLACE(CONVERT(VARCHAR(10), GETDATE(), 8), ':', '') Set @FileName='文檔路徑\資料庫名字_Trn_'+@FileFlag+'.trn' BackUp Log 資料庫名字 To Disk=@FileName with init
備份文件的命名格式為:資料庫名字_備份類型(Full或Diff或Trn的一種)_時間格式.文件類型(bak或trn的一種)
其中的時間格式為:年月日時分秒 ,例如:20190423140813。
例如,資料庫TestRestoreOP的備份文件如下:
我們花費篇章來說明備份文件的格式化,主要是因為【一鍵】還原的基礎是文件的標準化。
相應的還原命令如下:
----完整備份還原 RESTORE DATABASE 資料庫名字 FROM DISK = '完整備份的文件'---'TTTTTTT.BAK' WITH NORECOVERY, MOVE '資料庫名字_Data' TO 'D:\指定路徑\資料庫名字_Data.mdf', MOVE '資料庫名字_Log' TO 'D:\指定路徑\資料庫名字_Log.ldf' ----差異備份還原 RESTORE DATABASE 資料庫名字 FROM DISK = '差異備份的文件'------'SSSSSSSSS.BAK' WITH NORECOVERY, MOVE '資料庫名字_Data' TO 'D:\指定路徑\資料庫名字_Data.mdf', MOVE '資料庫名字_Log' TO 'D:\指定路徑\資料庫名字_Log.ldf' ----log備份還原 RESTORE Log 資料庫名字 FROM DISK ='事務日誌備份的文件' -----'XXXXXXXX.trn' WITH NORECOVERY
2.遠程備份文件的【一鍵】還原
實際的生產中,我們常將備份文件Copy至遠程伺服器上,所以還原的時候,還要將這些文件Copy到指定服務上再進行還原。還有一種情況,就是Log還原可能需要逐一還原多個日誌文件,有時候,甚至十幾個文件需要還原。
針對這種這種情況,日常工作中,我們逐漸提煉成了以下SQL,替換參數後,基本實現 一鍵還原。
主要實現的功能有四點:
(1)將遠程Server 上的指定備份路徑下的文件Copy值本地指定路徑;(如果文件以Copy值本地,這一步可以省略,對應的代碼為1和2部分)
(2) 將這些文件屬性讀到表BackupFile;
(3)根據文件命名的時間屬性,還原最近的一個完整備份 和一個差異備份;
(4)還原差異備份後產生的所有日誌備份。
3.代碼實現
---0 --定義要還原的資料庫名字 DECLARE @Cmd varchar (1024) DECLARE @dbName sysname Set @dbName='TestRestoreOP' --- 1 --定義遠程備份文件所在目錄 DECLARE @sourceFile NVARCHAR(500) SET @sourceFile = '\\169.XXX.XXX.XXX\d$\SQL_BackFile' ----2 -- 將遠程備份的目錄,Copy至本地 D:\SQL_RestoreFile 目錄下,MAXAGE:3 代表Copy最近3天的文件 SET @Cmd=('master.dbo.xp_cmdshell '+'''ROBOCOPY.exe "'+@sourceFile+'" "D:\SQL_RestoreFile" *.* /E /XC /XN /X /MAXAGE:3 /MINAGE:0 ''') print @Cmd EXEC (@Cmd) Print '將遠程需要還原的文件Copy至本地' ----3 -- 獲取還原文件List DECLARE @Path VARCHAR(260) SET @Path = 'D:\SQL_RestoreFile' IF RIGHT(@Path, 1) <> '\' SET @Path = @Path + '\' Print @Path ----判斷表BackupFile是否已經存在,不存在則創建 IF (SELECT COUNT(*) FROM SYS.sysobjects WHERE name='BackupFile'and xtype='U')=0 BEGIN CREATE TABLE BackupFile ( id INT , --編號 directory VARCHAR(260) , --路徑 depth INT , --深度,相對與@path IsFile BIT , filename VARCHAR(260), IsRestore int ,--是否還原 )--0文件夾1文件名成 END Truncate table BackupFile -----判斷表TMP_BackupFile是否已經存在,存在則刪除再創建 IF (SELECT COUNT(*) FROM SYS.sysobjects WHERE name='TMP_BackupFile'and xtype='U')<>0 BEGIN DROP TABLE TMP_BackupFile END CREATE TABLE TMP_BackupFile ( id INT IDENTITY , --編號 directory VARCHAR(260) , --路徑 depth INT , --深度,相對與@path IsFile BIT , filename VARCHAR(260), IsRestore int ,--是否還原 )--0文件夾1文件名成 ----將@Path 目錄下結構讀入到表TMP_BackupFile中 INSERT TMP_BackupFile ( directory , depth , IsFile ) EXEC master.dbo.xp_dirtree @path = @Path, @depth = 0, @file = 1 update TMP_BackupFile set filename=directory,IsRestore=0 Print '將需要還原的文件信息讀入到表TMP_BackupFile中' -----設置不需要還原的資料庫文件,即刪除 DELETE FROM dbo.TMP_BackupFile WHERE directory NOT LIKE '%'+@dbName+'%' ----設置刪除不符合日期規則的文件 DELETE FROM dbo.TMP_BackupFile WHERE left(right([filename],18),14)<'20190413015000' -----更新目錄 UPDATE TMP_BackupFile SET directory = @Path + directory WHERE depth = 1 ------ if exists( select * from TMP_BackupFile WHERE depth > 1) begin Print 'Error:備份文件所在的路徑不對,或者@Path包含了不應該存在的文件夾目錄!' end ------- INSERT INTO BackupFile (directory, depth, IsFile, [filename], IsRestore) SELECT B.directory, B.depth, B.IsFile, B.[filename], B.IsRestore FROM TMP_BackupFile B left join BackupFile e on B.[filename]=e.[filename] where e.[filename] is null ---4 --定義5/6/7 步驟需要的參數 DECLARE @filename NVARCHAR(500) DECLARE @backupPath NVARCHAR(500) -- 5 -- 找到需要還原的完整備份文件,進行完整還原 SELECT top 1 @filename =[filename] FROM BackupFile WHERE IsRestore=0 AND directory LIKE '%FULL%.bak' ORDER BY left(right([filename],18),14) desc Print @filename Print 'Msg:完整備份文件:' + @filename + '開始還原!' SELECT @backupPath=directory FROM BackupFile WHERE filename=@filename AND IsRestore=0 print @dbName SET @cmd = 'RESTORE DATABASE [' + @dbName + '] FROM DISK = ''' + @backupPath + ''' WITH FILE = 1, MOVE N'''+@dbName+''' TO N''D:\sql_data\'+@dbName+'.MDF'', MOVE N'''+@dbName+'_Log'' TO N''D:\sql_log\'+@dbName+'.LDF'',NORECOVERY, NOUNLOAD, STATS = 5' exec (@cmd) PRINT @cmd UPDATE BackupFile SET IsRestore=1 WHERE filename=@filename AND IsRestore=0 Print 'Msg:完整備份文件:' + @filename + '還原完成!' -- 6 --- 找到需要還原的差異備份文件,進行增量還原 SELECT top 1 @filename=[filename] FROM BackupFile WHERE IsRestore=0 AND directory LIKE '%Diff%.bak' ORDER BY left(right([filename],18),14) desc print @filename Print 'Msg:獲取得知需要還原的差異備份文件:' + @filename + ',此時將不需要還原的差異文件/日誌文件設置為不需要還原' update BackupFile set IsRestore=10 WHERE IsRestore=0 AND (directory LIKE '%Diff%.bak' or directory LIKE '%TRN%.TRN' ) and left(right([filename],18),14)<left(right( @filename,18),14) Print 'Msg:差異備份文件:' + @filename + '開始還原!' SELECT @backupPath=directory FROM BackupFile WHERE filename=@filename AND IsRestore=0 SET @cmd = 'RESTORE DATABASE [' + @dbName + '] FROM DISK = ''' + @backupPath + ''' WITH NORECOVERY' exec(@cmd) PRINT @cmd UPDATE BackupFile SET IsRestore=1 WHERE filename=@filename AND IsRestore=0 Print 'Msg:差異備份文件:' + @filename + '還原完成!' -- 7 --日誌備份文件還原 DECLARE filenames CURSOR FOR SELECT [filename] FROM BackupFile WHERE IsRestore=0 AND directory LIKE '%TRN%.TRN' ORDER BY left(right([filename],18),14) asc OPEN filenames -- Loop through all the files for the database FETCH NEXT FROM filenames INTO @filename WHILE @@FETCH_STATUS = 0 BEGIN Print 'Msg:日誌備份文件:' + @filename + '開始還原!' SELECT @backupPath=directory FROM BackupFile WHERE filename=@filename AND IsRestore=0 SET @cmd = 'RESTORE LOG [' + @dbName + '] FROM DISK = ''' +@backupPath+ ''' WITH NORECOVERY' exec(@cmd) UPDATE BackupFile SET IsRestore=1 WHERE filename=@filename AND IsRestore=0 Print 'Msg:日誌備份文件:' + @filename + '還原完成!' PRINT @cmd FETCH NEXT FROM filenames INTO @filename END CLOSE filenames DEALLOCATE filenames -- 8 -- 將資料庫的狀態由真正還原Restore正常狀態! Print '將資料庫的狀態由真正還原Restore正常狀態!' SET @cmd = 'RESTORE DATABASE [' + @dbName + '] WITH RECOVERY' PRINT @cmd Print '資料庫所有的還原操作都已完成!'---0 --定義要還原的資料庫名字 DECLARE @Cmd varchar (1024) DECLARE @dbName sysname Set @dbName='TestRestoreOP' --- 1 --定義遠程備份文件所在目錄 DECLARE @sourceFile NVARCHAR(500) SET @sourceFile = '\\169.XXX.XXX.XXX\d$\SQL_BackFile' ----2 -- 將遠程備份的目錄,Copy至本地 D:\SQL_RestoreFile 目錄下,MAXAGE:3 代表Copy最近3天的文件 SET @Cmd=('master.dbo.xp_cmdshell '+'''ROBOCOPY.exe "'+@sourceFile+'" "D:\SQL_RestoreFile" *.* /E /XC /XN /X /MAXAGE:3 /MINAGE:0 ''') print @Cmd EXEC (@Cmd) Print '將遠程需要還原的文件Copy至本地' ----3 -- 獲取還原文件List DECLARE @Path VARCHAR(260) SET @Path = 'D:\SQL_RestoreFile' IF RIGHT(@Path, 1) <> '\' SET @Path = @Path + '\' Print @Path ----判斷表BackupFile是否已經存在,不存在則創建 IF (SELECT COUNT(*) FROM SYS.sysobjects WHERE name='BackupFile'and xtype='U')=0 BEGIN CREATE TABLE BackupFile ( id INT , --編號 directory VARCHAR(260) , --路徑 depth INT , --深度,相對與@path IsFile BIT , filename VARCHAR(260), IsRestore int ,--是否還原 )--0文件夾1文件名成 END Truncate table BackupFile -----判斷表TMP_BackupFile是否已經存在,存在則刪除再創建 IF (SELECT COUNT(*) FROM SYS.sysobjects WHERE name='TMP_BackupFile'and xtype='U')<>0 BEGIN DROP TABLE TMP_BackupFile END CREATE TABLE TMP_BackupFile ( id INT IDENTITY , --編號 directory VARCHAR(260) , --路徑 depth INT , --深度,相對與@path IsFile BIT , filename VARCHAR(260), IsRestore int ,--是否還原 )--0文件夾1文件名成 ----將@Path 目錄下結構讀入到表TMP_BackupFile中 INSERT TMP_BackupFile ( directory , depth , IsFile ) EXEC master.dbo.xp_dirtree @path = @Path, @depth = 0, @file = 1 update TMP_BackupFile set filename=directory,IsRestore=0 Print '將需要還原的文件信息讀入到表TMP_BackupFile中' -----設置不需要還原的資料庫文件,即刪除 DELETE FROM dbo.TMP_BackupFile WHERE directory NOT LIKE '%'+@dbName+'%' ----設置刪除不符合日期規則的文件 DELETE FROM dbo.TMP_BackupFile WHERE left(right([filename],18),14)<'20190413015000' -----更新目錄 UPDATE TMP_BackupFile SET directory = @Path + directory WHERE depth = 1 ------ if exists( select * from TMP_BackupFile WHERE depth > 1) begin Print 'Error:備份文件所在的路徑不對,或者@Path包含了不應該存在的文件夾目錄!' end ------- INSERT INTO BackupFile (directory, depth, IsFile, [filename], IsRestore) SELECT B.directory, B.depth, B.IsFile, B.[filename], B.IsRestore FROM TMP_BackupFile B left join BackupFile e on B.[filename]=e.[filename] where e.[filename] is null ---4 --定義5/6/7 步驟需要的參數 DECLARE @filename NVARCHAR(500) DECLARE @backupPath NVARCHAR(500) -- 5 -- 找到需要還原的完整備份文件,進行完整還原 SELECT top 1 @filename =[filename] FROM BackupFile WHERE IsRestore=0 AND directory LIKE '%FULL%.bak' ORDER BY left(right([filename],18),14) desc Print @filename Print 'Msg:完整備份文件:' + @filename + '開始還原!' SELECT @backupPath=directory FROM BackupFile WHERE filename=@filename AND IsRestore=0 print @dbName SET @cmd =