在個人數據庫實例中,有不少下圖所示的數據庫,這些數據庫的名稱是有規律的,每一個數據庫包含的表都是相同的,其中2個表是相似流水記錄的表,表的數據量會比較大,佔用的空間有幾十G到上百G不等,這2個表相對於其它的配置表來講是比較不重要的。html
如今有一個需求就是對數據庫進行備份,容許丟失這兩個表的數據,保留重要的配置表數據,你是否遇到過一樣的問題呢?這個時候你會怎麼作呢?你有什麼方案呢?有什麼方法能夠快速備份這些數據庫呢?sql
(Figure1:數據庫列表)shell
閱讀本文以前你能夠先參考:SQL Server 批量完整備份數據庫
經過上面的描述,其中很重要的一點就是每一個數據庫中有2個大表,並且這些數據是不重要的,那麼咱們對這2個大表作表分區,把大數據放到其它文件組中,只留重要的配置表在主文件組(PRIMARY)中,接着就能夠對主文件組進行備份,這樣既知足了備份重要表數據,並且不會形成備份文件過大、佔用磁盤空間、備份時間過長等問題。服務器
肯定了方向以後咱們接着考慮做業的問題,經過做業備份相似Figure1的數據庫,有下面兩種方案可供選擇:測試
(Figure2:做業列表)大數據
(Figure3:做業列表)spa
Figure2是一個方案,這些做業是能夠自動化建立,可是會用到批處理,代碼會複雜一點,惟一的缺點就是當新建立了數據庫,是沒法自動備份的(不過能夠經過專門建立一個監控數據庫的新建、刪除狀態的Job來解決這個問題)詳情請參考:SQL Server 批量主分區備份(Multiple Jobs)3d
Figure3就是咱們這篇文章須要講述的方案,這裏把全部的數據庫的備份都集中到一個做業中,這個方案有如下缺點:代理
1) 整個備份過程是串行的;
2) 若是沒有異常處理,那麼後面的數據庫就沒有辦法備份了;
3) 在做業執行的時候對服務器壓力比較大(沒有分散執行時間);
4) 作自己的msdb數據庫中記錄的做業日誌也沒有那麼清晰,排錯比較困難(只有整個做業的信息,msdb.dbo.sysjobhistory的message字段保存不了太多信息),須要本身建立表進行記錄;
儘管有以上的缺點,可是也是有優勢的:當新建立了一個相似的數據庫(業務須要),這個時候做業也會備份這個數據,不用人工去建立做業;另外還有一個,就是當數據庫多而小的時候,這個方案特別有用;下面就來說講這個Job實現的具體步驟。
實現步驟概要:
1. 批量建立文件夾;
2. 建立維護表:[JobLog]和[ErrorLog];
3. 建立備份全部數據庫的SQL腳本;
4. 建立Job執行上面的腳本;
(一) 爲了方便管理備份文件,咱們爲每一個數據庫建立單獨的文件夾,下面的SQL代碼實現根據數據庫批量建立數據庫名對應的文件夾,使用了遊標循環數據庫名進行建立文件夾,執行cmd命令須要開啓數據庫的xp_cmdshell開關;
--批量建立文件夾 EXEC sp_configure 'show advanced options', 1 RECONFIGURE EXEC sp_configure 'xp_cmdshell', 1 RECONFIGURE DECLARE @DBName VARCHAR(100) DECLARE @SQL VARCHAR(1000) DECLARE CurDBName CURSOR FOR SELECT name FROM sys.databases WHERE name LIKE '%Opinion%' AND STATE =0 OPEN CurDBName FETCH NEXT FROM CurDBName INTO @DBName WHILE @@FETCH_STATUS = 0 BEGIN SET @SQL = 'mkdir E:\DBBackup\' + @DBName EXEC xp_cmdshell @SQL FETCH NEXT FROM CurDBName INTO @DBName END CLOSE CurDBName DEALLOCATE CurDBName EXEC sp_configure 'show advanced options', 0 RECONFIGURE EXEC sp_configure 'xp_cmdshell', 0 RECONFIGURE
執行上面的腳本後,會在E:\DBBackup\目錄下建立以下圖所示的文件夾:
(Figure4:建立的文件夾)
(二) 對備份的維護,我但願能夠了解到全部數據庫的備份狀況,因此下面建立2個維護表:[JobLog]和[ErrorLog],這兩個表用於記錄做業的執行狀況,經過這兩個表,能夠實現如Figure五、Figure6的效果;
--做業記錄表 USE [msdb] GO CREATE TABLE [dbo].[JobLog]( [Id] [int] IDENTITY(1,1) NOT NULL, [DB_Name] [varchar](50) NULL, [Backup_Date] [int] NULL, [Backup_Time] [int] NULL, [Backup_Duration] [int] NULL, [Backup_Type] [char](4) NULL, CONSTRAINT [PK_JobLog] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] --錯誤記錄表 USE [msdb] GO CREATE TABLE [dbo].[ErrorLog]( [Id] [int] IDENTITY(1,1) NOT NULL, [DB_Name] [varchar](50) NOT NULL, [Backup_Time] [datetime] NOT NULL CONSTRAINT [DF_ErrorLog_Backup_Time] DEFAULT (getdate()), [Messages] [nvarchar](500) NULL, CONSTRAINT [PK_ErrorLog] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
(三) 下面的代碼實現了主分區完整備份和主分區差別備份(主分區可參考:SQL Server 維護計劃備份主分區),當是星期一的深夜的時候,咱們作完整備份,若是是其它時候咱們就作差別備份,具體是何時,這個就經過計劃裏面的時候來控制了(計劃的執行時間爲星期1、星期3、星期五,這就表明星期一深夜作了完整備份、星期三和星期五分別作了差別備份)。(備份實踐可參考:SQL Server 2008 維護計劃實現數據庫備份)
下面是生成的備份文件命名的範例,這樣的備份文件的命名能夠方便維護,並且直觀知道備份文件建立的時間,能夠精確到秒,文件名重複的概率不大;
DBName _Primary_Full_2013_01_14_002007.bak
DBName_Primary_Diff_2013_01_16_002034.bak
下面是整個批量備份數據庫的核心SQL腳本,若是你是建立維護計劃,那能夠把這個SQL放到「執行 T-SQL 語句」任務,若是是建立Job的,能夠放到做業的步驟裏;
--批量備份數據庫 DECLARE @DBName VARCHAR(100) DECLARE @CurrentTime VARCHAR(50) DECLARE @FileName VARCHAR(200) DECLARE @WithType CHAR(20) DECLARE @Backup_Date VARCHAR(50) DECLARE @Backup_Time VARCHAR(50) DECLARE @Backup_Duration VARCHAR(50) DECLARE @Backup_Start DATETIME DECLARE @Backup_End DATETIME DECLARE @BackupType CHAR(4) DECLARE @SQL VARCHAR(MAX) --防止做業遺漏備份 INSERT INTO [msdb].[dbo].[JobLog]([DB_Name],[Backup_Date],[Backup_Time],[Backup_Duration],[Backup_Type]) SELECT name,0,0,0,NULL FROM sys.databases WHERE name LIKE '%Opinion%' AND STATE =0 AND name NOT IN (SELECT DISTINCT [DB_Name] FROM [msdb].[dbo].[JobLog]) ORDER BY name DECLARE CurDBName CURSOR FOR SELECT name FROM sys.databases WHERE name LIKE '%Opinion%' AND STATE =0 ORDER BY name OPEN CurDBName FETCH NEXT FROM CurDBName INTO @DBName WHILE @@FETCH_STATUS = 0 BEGIN --Execute Backup --捕獲異常 BEGIN TRY PRINT @DBName SET @CurrentTime = REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR, GETDATE(), 120 ),'-','_'),' ','_'),':','') IF(DATEPART(DW, GETDATE()) = 2)--星期一 BEGIN SET @FileName = 'E:\DBBackup\'+@DBName+'\'+@DBName+'_Primary_Full_' + @CurrentTime+'.bak' SET @WithType = ' FORMAT' SET @BackupType = 'Full' END ELSE BEGIN SET @FileName = 'E:\DBBackup\'+@DBName+'\'+@DBName+'_Primary_Diff_' + @CurrentTime+'.bak' SET @WithType = ' DIFFERENTIAL,FORMAT' SET @BackupType = 'Diff' END SET @Backup_Start = GETDATE() SET @SQL = ' --1設置完整模式 ALTER DATABASE ['+@DBName+'] SET RECOVERY FULL WITH NO_WAIT; --2備份主分區 BACKUP DATABASE ['+@DBName+'] FILEGROUP=''PRIMARY'' TO DISK='''+@FileName+''' WITH '+@WithType+'; --3設置簡單模式 ALTER DATABASE ['+@DBName+'] SET RECOVERY SIMPLE WITH NO_WAIT; ' EXEC(@SQL) SET @Backup_End = GETDATE() SET @Backup_Date = CONVERT(VARCHAR, GETDATE(),112) SET @Backup_Time = REPLACE(CONVERT(VARCHAR, GETDATE(),24),':','') SET @Backup_Duration = CONVERT(VARCHAR,DATEDIFF(ss,@Backup_Start,@Backup_End)) PRINT @Backup_Date +@Backup_Time +@Backup_Duration SET @SQL = ' INSERT INTO [msdb].[dbo].[JobLog]([DB_Name],[Backup_Date],[Backup_Time],[Backup_Duration],[Backup_Type]) VALUES('''+@DBName+''','+@Backup_Date+','+@Backup_Time+','+@Backup_Duration+','''+@BackupType+'''); ' EXEC(@SQL) END TRY BEGIN CATCH INSERT INTO [dbo].[ErrorLog]([DB_Name],[ErrorMessage]) VALUES(@DBName,ERROR_MESSAGE()) --ROLLBACK TRANSACTION END CATCH --Get Next DataBase FETCH NEXT FROM CurDBName INTO @DBName END CLOSE CurDBName DEALLOCATE CurDBName
這個備份腳本中使用了遊標循環獲取數據庫名進行備份,在【--防止做業遺漏備份】標籤的SQL語句是爲了保證記錄表[JobLog]每次執行都有新的記錄,即便備份失敗(如何查看後面會講到)也能夠觀察到對應的記錄;
腳本中加入了異常處理,能夠有效的防止某個數據庫備份失敗後,後面數據庫的備份不受影響,把異常信息插入到[ErrorLog]。
SQL代碼裏面強制了星期一進行主分區的完整備份,其它何時作差別備份,這個就徹底由做業中計劃來控制(若是你想,你能夠經過做業中的計劃來調整天天都進行差別備份)。
(四) 下面的代碼實現了刪除備份文件,從下面的代碼實現刪除14天以前的備份文件,這個能夠做爲第三步驟的下一個步驟,可是須要注意有相應的機制能夠檢測到備份失敗的數據庫,否則一段時間備份都失敗了,會形成最後沒有了備份文件(能夠經過郵件查詢[ErrorLog]進行預警,能夠參考:SQL Server 建立數據庫郵件)
--刪除14天以前的備份文件 DECLARE @DeleteDate DATETIME SET @DeleteDate = DATEADD(DAY, -14, GETDATE()) EXECUTE MASTER.SYS.XP_DELETE_FILE 0, N'E:\DBBackup\', N'bak', @DeleteDate
(五) 查看做業的運行狀況;
--行轉列(備份類型) DECLARE @s NVARCHAR(MAX) SET @s='' SELECT @s=@s+','+quotename([Backup_Date])+'=MAX(CASE WHEN [Backup_Date]='+quotename([Backup_Date],'''')+' THEN [Backup_Type] ELSE NULL END)' FROM [msdb].[dbo].[JobLog] GROUP BY [Backup_Date] ORDER BY [Backup_Date] PRINT @s EXEC('SELECT [DB_Name] '+@s+' FROM [msdb].[dbo].[JobLog] GROUP BY [DB_Name] ORDER BY [DB_Name]')
(Figure5:做業備份類型)
--行轉列(執行時間) DECLARE @s NVARCHAR(MAX) SET @s='' SELECT @s=@s+','+quotename([Backup_Date])+'=MAX(CASE WHEN [Backup_Date]='+quotename([Backup_Date],'''')+' THEN [Backup_Duration] ELSE NULL END)' FROM [msdb].[dbo].[JobLog] GROUP BY [Backup_Date] ORDER BY [Backup_Date] PRINT @s EXEC('SELECT [DB_Name] '+@s+' FROM [msdb].[dbo].[JobLog] GROUP BY [DB_Name] ORDER BY [DB_Name]')
(Figure6:做業執行時間)
既然作了上面主文件組的備份,固然咱們須要去測試這個主文件組的還原了,這樣才能夠當遇到問題能夠快速還原備份文件,達到還原數據的目的;
接下來會在另一篇文章裏面專門講解;
sp_update_schedule (Transact-SQL)