SQL Server 批量主分區備份(One Job)


一.本文所涉及的內容(Contents)

  1. 本文所涉及的內容(Contents)
  2. 背景(Contexts)
  3. 案例分析(Case)
  4. 實現代碼(SQL Codes)
  5. 主分區完整、差異還原(Primary Backup And Restore)
  6. 參考文獻(References)

二.背景(Contexts)

  在我的數據庫實例中,有很多下圖所示的數據庫,這些數據庫的名稱是有規律的,每個數據庫包含的表都是相同的,其中2個表是類似流水記錄的表,表的數據量會比較大,占用的空間有幾十G到上百G不等,這2個表相對於其它的配置表來說是比較不重要的。

  現在有一個需求就是對數據庫進行備份,允許丟失這兩個表的數據,保留重要的配置表數據,你是否遇到過同樣的問題呢?這個時候你會怎么做呢?你有什么方案呢?有什么方法可以快速備份這些數據庫呢?

wps_clip_image-30433

(Figure1:數據庫列表)

閱讀本文之前你可以先參考:SQL Server 批量完整備份

 

三.案例分析(Case)

  通過上面的描述,其中很重要的一點就是每個數據庫中有2個大表,而且這些數據是不重要的,那么我們對這2個大表做表分區,把大數據放到其它文件組中,只留重要的配置表在主文件組(PRIMARY)中,接着就可以對主文件組進行備份,這樣既滿足了備份重要表數據,而且不會造成備份文件過大、占用磁盤空間、備份時間過長等問題。

  確定了方向之后我們接着考慮作業的問題,通過作業備份類似Figure1的數據庫,有下面兩種方案可供選擇:

wps_clip_image-31239

(Figure2:作業列表)

wps_clip_image-21511

(Figure3:作業列表)

  Figure2是一個方案,這些作業是可以自動化創建,但是會用到批處理,代碼會復雜一點,唯一的缺點就是當新創建了數據庫,是無法自動備份的(不過可以通過專門創建一個監控數據庫的新建、刪除狀態的Job來解決這個問題)詳情請參考:SQL Server 批量主分區備份(Multiple Jobs)

  Figure3就是我們這篇文章需要講述的方案,這里把所有的數據庫的備份都集中到一個作業中,這個方案有以下缺點:

    1) 整個備份過程是串行的;

    2) 如果沒有異常處理,那么后面的數據庫就沒有辦法備份了;

    3) 在作業執行的時候對服務器壓力比較大(沒有分散執行時間);

    4) 做本身的msdb數據庫中記錄的作業日志也沒有那么清晰,排錯比較困難(只有整個作業的信息,msdb.dbo.sysjobhistory的message字段保存不了太多信息),需要自己創建表進行記錄;

  盡管有以上的缺點,但是也是有優點的:當新創建了一個類似的數據庫(業務需要),這個時候作業也會備份這個數據,不用人工去創建作業;另外還有一個,就是當數據庫多而小的時候,這個方案特別有用;下面就來講講這個Job實現的具體步驟。

 

四.實現代碼(SQL Codes)

實現步驟概要:

  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\目錄下創建如下圖所示的文件夾:

wps_clip_image-18848

(Figure4:創建的文件夾)

 

(二) 對備份的維護,我希望可以了解到所有數據庫的備份情況,所以下面創建2個維護表:[JobLog]和[ErrorLog],這兩個表用於記錄作業的執行情況,通過這兩個表,可以實現如Figure5、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 維護計划備份主分區),當是星期一的深夜的時候,我們做完整備份,如果是其它時候我們就做差異備份,具體是什么時候,這個就通過計划里面的時候來控制了(計划的執行時間為星期一、星期三、星期五,這就代表星期一深夜做了完整備份、星期三和星期五分別做了差異備份)。(備份實踐可參考: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]')

wps_clip_image-5181

(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]')

wps_clip_image-20380

(Figure6:作業執行時間)

 

五.主分區完整、差異還原(Primary Backup And Restore)

  既然做了上面主文件組的備份,當然我們需要去測試這個主文件組的還原了,這樣才可以當遇到問題可以快速還原備份文件,達到還原數據的目的;

  接下來會在另外一篇文章里面專門講解;

 

六.參考文獻(References)

sp_update_schedule (Transact-SQL)

如何修改 SQL Server 代理主作業 (Transact-SQL)

bat實現文件字符串替換

Sqlcmd 使用


免責聲明!

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



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