(4.21)sql server备份策略深入探究

1、SQL Server自动化运维 - 备份(一)业务数据库

 

为了能够恢复数据,数据库运维基础就是备份,备份自动化也是运维自动化首要进行的。

笔者的备份自动化,通过配置表快速配置为前提,同时记录备份过程,尽可能的减少人工操作。首先将SQL Server备份按用途分:

1、 业务数据库备份--本文主要内容

SQL Server提供多种备份方式,为业务数据库备份选择何种备份策略,可根据各自的数据量和业务情况而定。

备份策略需求:

  • 可恢复到备份之前的任意时间点,尽量减少数据丢失
  • 单个备份数据库已达TB
  • 考虑还原效率、不可追加过多的日志

备份策略制定:

  • 完整备份:每周一执行一次
  • 差异备份:每天执行一次,周一不执行
  • 日志备份:每1小时一次
  • 备份副本:保存多份备份副本;上传一份副本到远程磁盘dbbackup文件夹
  • 备份归档:归档远程磁盘备份到dbbackuphistory文件夹,只保留当月最早完整备份和所有日志备份,删除差异备份
  • 通过配置表控制是否备份,备份路径等;并记录备份信息,备份大小,开始时间,结束时间等

注:在执行完整或差异备份的同时,可同时执行日志备份。

2、系统数据库、配置数据库、高可用配置、权限、Job、SSIS等备份;以下简称为“灾备”--后续文章介绍

   灾备的目的在于,发生重大服务器故障,可迅速通过灾备恢复原有配置,权限用户等等。

一、备份架构

基础备份架构如图所示:

方案一、将数据先备份到所在服务器的本地磁盘,再上传到远程磁盘柜(多份数据副本),最后针对磁盘柜的备份进行归档处理。之所以先备份到本地,是考虑备份最好保存多份,以防止文件损坏。

方案二、若本地磁盘空间不足,或者io压力较大,可直接备份到远程。

二、配置表

指定两张配置表,BackupRestoreSetting为备份配置信息,备份路径,上传路径,是否备份,是否上传控制;BackupFileList记录备份信息,备份文件名称、大小、开始时间、结束时间等。

2.1、BackupRestoreSetting备份还原配置信息表

如下图所示,插入该数据库的备份还原配置信息,备份磁盘路径,上传路径,是否备份是否上传等信息。后续脚本封装将读取这些配置信息进行备份。

注:由于还原是以备份信息为基础,所以配置信息需要放在一起。此处暂时刻忽略还原内容。

复制代码
--运维配置库,收集本地服务器所有自动化信息;包括dmv,扩展事件,计数器,备份,日常维护脚本封装等。
USE [Configdb]
GO
--备份还原配置表
CREATE TABLE [dbo].[BackupRestoreSetting](
    [Servername] [sysname] NOT NULL,--服务器名称
    [DBname] [sysname] NOT NULL,--数据库名称
    [V_DBname] [nvarchar](128) NULL,--还原数据库名称
    [Backup_drive] [char](1) NULL,--备份磁盘
    [Backup_path] [varchar](100) NULL,--备份路径
    [Restore_drive] [char](1) NULL,--还原磁盘
    [Restore_path] [varchar](100) NULL,--还原路径
    [Copy_path] [varchar](100) NULL,--上传路径
    [IsBackup] [char](1) NULL,--是否备份
    [IsCopy] [char](1) NULL,--是否上传
    [IsRestore] [char](1) NULL,--是否还原
    [RestoreStatus] [char](1) NULL,--还原状态
    [Priority] [smallint] NULL,--还原优先级
    [Net_Ip] [varchar](100) NULL,--远程磁盘柜IP
 CONSTRAINT [PK_BackupRestoreSetting] PRIMARY KEY CLUSTERED 
(
    [Servername] ASC,
    [DBname] ASC
)
) ON [PRIMARY]
复制代码

2.2、BackupFilelist备份信息记录表

记录备份大小,开始时间,结束时间,上传时间等等;以便统计和备份异常处理。

复制代码
--备份信息记录表
CREATE TABLE [dbo].[BackupFilelist](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Servername] [varchar](50) NULL,--服务器名称
    [Dbname] [varchar](50) NULL,--数据库名称
    [Backupset] [varchar](4) NULL,--备份模式,完整FULL 差异DIFF 日志LOG
    [Filename] [varchar](100) NULL,--备份文件名称
    [Filesize] [varchar](20) NULL,--备份文件大小
    [Backup_start_time] [datetime] NULL,--备份开始时间
    [Backup_end_time] [datetime] NULL,--备份结束时间
    [Copy_end_time] [datetime] NULL,--上传开始时间
    [Copy_status] [char](1) NULL,--上传状态
    [ReCopyTimes] [int] NULL,--重复上传次数
    [Media_set_id] [int] NULL,--上传文件meidaid
    [Error_Msg] [varchar](max) NULL,--错误信息
    [Cmd] [varchar](max) NULL,--上传命令
 CONSTRAINT [PK_BackupFilelist] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)
)
GO
复制代码

三、spx_Backup_DelFile删除本地备份

若备份存放在本地,需要定期删除本地备份,以防止本地磁盘不足;建议在执行完整FULL备份之前来删除本地备份,以保证可快速还原完整备份之后的任意时间点。

删除本地备份脚本spx_Backup_DelFile

 

复制代码
USE [Configdb]
GO

/****************************** 功能描述:<本地备份文件删除>
*   创建者:<HuangCH〉
*   创建日期:<2015-12-03>
*   备注说明:<@Retain_weeks 保留周数,默认全部删除>
##########
Change Log
########## 
Date                 Changer             Description
--------------------------------------------------
<2015-12-03>       <HuangCH>            <新建>
--------------------------------------------------
***************************/

CREATE PROCEDURE [dbo].[spx_Backup_DelFile]
          @servername [SYSNAME],
          @dbname     [SYSNAME],
          @Retain_weeks      INT=0
AS
  SET nocount on 
  ----===============================
  DECLARE  @retcode INT  
  DECLARE  @cmd VARCHAR(2000)
  DECLARE  @backup_drive CHAR(1)--本地备份磁盘
  DECLARE  @backup_path VARCHAR(200)--本地备份路径'

  SELECT @backup_drive = backup_drive,
         @backup_path = backup_path

  FROM   dbo.BackupRestoreSetting WITH (nolock)
  WHERE  servername=@servername and dbname = @dbname
  
  IF @Retain_weeks=0
  BEGIN
    --删除备份
      SET @cmd='del '+@backup_drive +':\'+@backup_path+'\'+ @dbname + '_??????????????_*_???.bak'
      EXEC master..Xp_cmdshell @cmd
    END 
    ELSE IF @Retain_weeks>0
    BEGIN
       DECLARE @delday Datetime
       SET @delday=CONVERT(VARCHAR,DATEADD(WEEK,-@Retain_weeks,GETDATE()),23)
       WHILE @delday>=DATEADD(WEEK,-@Retain_weeks-3,GETDATE())
       BEGIN 
         SET @delday=DATEADD(D,-1,@delday)
         SET @cmd='del '+@backup_drive +':\'+@backup_path+'\'+ @dbname + '_'+CONVERT(VARCHAR,@delday,112)+'*_*_???.bak'
         EXEC master..Xp_cmdshell @cmd
       END

    END
复制代码

 

例如:删除本地sqlmonitor服务器下configdb备份;插入配置信息,传入@servername和@dbname 可删除某个数据库的本地备份

复制代码
USE Configdb
GO
--插入配置信息
INSERT INTO [dbo].[BackupRestoreSetting](Servername,DBname,V_DBname,Backup_drive,Backup_path,Restore_drive,Restore_path,Copy_path,IsBackup,IsCopy)
VALUES('sqlmonitor','configdb','configdb','d','backup','d','sqldasta','m:\dbbackup\sqlmonitor','T','F')
GO
--完整备份:确认d:\backup目录是否存在
EXEC spx_Backup_DelFile @servername='sqlmonitor',@dbname='configdb',@Retain_weeks=0--默认为0,若1值则多保留1周
复制代码

四、spx_Backup_DB备份数据库

复制代码
USE [Configdb]
GO
GO
/****************************** 功能描述:<备份数据库>
*   创建者:<HuangCH〉
*   创建日期:<2015-12-03>
*   备注说明:<
1、备份类型只能是"FULL","DIFF","LOG"'
>
##########
Change Log
########## 
Date                 Changer             Description
--------------------------------------------------
<2015-12-03>       <HuangCH>            <新建>

--------------------------------------------------
***************************/

ALTER proc [dbo].[spx_Backup_DB]
@servername [varchar](50),
@dbname [sysname],
@backupset [varchar](4)
as
----确定linkedserver是否正常
--DECLARE  @servername [VARCHAR](50),
--         @dbname     [SYSNAME],
--         @backupset  [VARCHAR](4)
/*确认参数信息是否正确*/
IF @backupset NOT IN ('full','log','diff')
  BEGIN
    PRINT '''' + Upper(@backupset) + ''' is not a valid value for argument @backupset.'
    RETURN -1000
  END
IF Db_id(@dbname) IS NULL
  BEGIN
    PRINT 'Database ''' + @dbname + ''' not found.'
    RETURN -2000
  END
IF NOT EXISTS(SELECT TOP 1 1 FROM dbo.BackupRestoreSetting  WHERE servername = @servername AND dbname = @dbname) 
  BEGIN 
    RAISERROR ('备份还原配置表信息不存在,请确认',16,1)
    RETURN -4000
  END  
DECLARE  @version VARCHAR(4)--sql server版本
DECLARE  @Backup_dirve CHAR(1)--备份磁盘
DECLARE  @backup_path VARCHAR(1000)--备份路径
DECLARE  @copy_path VARCHAR(50)--上传路径
DECLARE  @IsCopy CHAR(1)--是否已经上传
DECLARE  @filename VARCHAR(2000)--备份文件名称
DECLARE  @retcode INT
DECLARE  @errorMessage VARCHAR(2000)
DECLARE  @netdevice CHAR(1)
DECLARE  @net_ip VARCHAR(20)
DECLARE  @id INT
DECLARE  @cmd VARCHAR(4000)
/*确定数据库版本*/
SET @version =CASE WHEN CONVERT(VARCHAR(20),Serverproperty('ProductVersion')) LIKE '9.0%' THEN '05'
                      WHEN CONVERT(VARCHAR(20),Serverproperty('ProductVersion')) LIKE '10%' THEN '08'
                      WHEN CONVERT(VARCHAR(20),Serverproperty('ProductVersion')) LIKE '11%' THEN '12'
                      WHEN CONVERT(VARCHAR(20),Serverproperty('ProductVersion')) LIKE '12%' THEN '14'
                      ELSE '16' END 

SELECT @Backup_dirve = backup_drive,
       @backup_path = backup_path,
       @copy_path = copy_path,
       @IsCopy = IsCopy,
       @net_ip = net_ip
FROM   dbo.BackupRestoreSetting WITH (NOLOCK)
WHERE  servername = @servername
       AND dbname = @dbname

/*确定备份文件名称*/
SET @filename = @dbname + '_' + REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(19),Getdate(),21),'-',''),' ',''),':','') + '_' + Upper(@backupset) + '_P' + @version + '.bak'


/*确定本地备份路径*/
SET @backup_path =  @Backup_dirve + ':\' + @backup_path + '\' + @filename
/*记录备份文件基本信息,和备份开始时间*/
INSERT INTO dbo.BackupFilelist
(
Servername,
Dbname,
Backupset,
Filename,
Filesize,
Backup_start_time,
Backup_end_time,
Copy_end_time,
Copy_status,
ReCopyTimes,
Media_set_id
)
VALUES     (@servername,
            @dbname,
            @backupset,
            @filename,
            NULL,
            Getdate(),
            NULL,
            NULL,
            NULL,
            NULL,
            NULL)
/*取记录id号*/
SET @ID=SCOPE_IDENTITY()
/*开始备份(log,full),覆盖现有备份集*/
BEGIN TRY
  IF @backupset='FULL' 
  BEGIN
    SET @cmd='BACKUP DATABASE ['+@dbname+'] TO DISK='''+@backup_path+CASE WHEN CONVERT(VARCHAR(20),Serverproperty('ProductVersion')) LIKE '9.0%' THEN  ''' WITH INIT' ELSE ''' WITH INIT,COMPRESSION' END 
  END
  ELSE IF @backupset='DIFF'
  BEGIN
    SET @cmd='BACKUP DATABASE ['+@dbname+'] TO DISK='''+@backup_path+CASE WHEN CONVERT(VARCHAR(20),Serverproperty('ProductVersion')) LIKE '9.0%' THEN  ''' WITH INIT,DIFFERENTIAL' ELSE ''' WITH INIT,COMPRESSION,DIFFERENTIAL' END 
  END
  ELSE
  BEGIN
    SET @cmd='BACKUP LOG ['+@dbname+'] TO DISK='''+@backup_path+CASE WHEN CONVERT(VARCHAR(20),Serverproperty('ProductVersion')) LIKE '9.0%' THEN  ''' WITH INIT' ELSE ''' WITH INIT,COMPRESSION' END 
  END 
  --PRINT @cmd
  EXEC (@cmd)
  
END TRY
BEGIN CATCH
  SELECT @retcode = @@ERROR,  @errorMessage = Error_message()
  UPDATE dbo.BackupFilelist
  SET    Error_Msg=@errorMessage,
         Cmd=@cmd
  WHERE  id = @id
  RAISERROR (@errorMessage,16,1)
  RETURN @retcode
END CATCH

/*记录备份结束时间*/
UPDATE dbo.BackupFilelist
SET    backup_end_time = Getdate(),
       media_set_id = (SELECT   TOP 1  media_set_id  FROM   msdb.dbo.backupmediafamily WITH (nolock) ORDER BY media_set_id Desc),
       Cmd=@cmd
WHERE  id = @id
/*记录备份文件大小*/

DECLARE  @filesize   VARCHAR(20),
         @tempString VARCHAR(400)
SET @cmd = 'DIR ' + @backup_path
CREATE TABLE #tbl (line NVARCHAR(255))
INSERT INTO #tbl
EXEC master.dbo.Xp_cmdshell @cmd
SELECT @tempString = line
FROM   #tbl
WHERE  line LIKE '%' + @filename + '%'
IF (@tempString LIKE '%:__ _M %')  --like '%:__ AM %' OR @tempString like '%:__ PM %')
  SELECT @filesize = REPLACE(Rtrim(Ltrim(Substring(@tempString,Charindex(':',@tempString) + 6,
                                                   Charindex(@filename,@tempString) - Charindex(':',@tempString) - 6))),
                             ',','')
ELSE
  SELECT @filesize = REPLACE(Rtrim(Ltrim(Substring(@tempString,Charindex(':',@tempString) + 3,
                                                   Charindex(@filename,@tempString) - Charindex(':',@tempString) - 3))),
                             ',','')
UPDATE dbo.BackupFilelist
SET    filesize = @filesize
WHERE  id = @id

/*开始上传备份文件*/
DECLARE  @ReCopyTimes INT
SET @ReCopyTimes = 0
RECOPYFLAG:
IF @IsCopy = 'T'
  BEGIN
    /*映射@netdevice远程*/
    SELECT @netdevice = Substring(Ltrim(@copy_path),1,1)
    BEGIN TRY
      EXEC spx_NetUse @drive = @netdevice  output,
                      @ip = @net_ip
    END TRY
    BEGIN CATCH
      SELECT @errorMessage = Error_message()
      RAISERROR (@errorMessage,16,1)
      RETURN -5000
    END CATCH

    /*确认拷贝路径是否存在*/
     SELECT @cmd = 'DIR ' + @netdevice + Substring(@copy_path,2,Len(@copy_path))
     EXEC @retcode = master..Xp_cmdshell @cmd
     IF @@ERROR = 0 AND @retcode <> 0
       BEGIN
          SELECT @cmd = 'MD ' + @netdevice + Substring(@copy_path,2,Len(@copy_path))
          EXEC @retcode = master..Xp_cmdshell @cmd
       END

    SET @cmd = 'copy ' + @backup_path + ' ' + @netdevice + Substring(@copy_path,2,Len(@copy_path))
 
    EXEC @retcode = master..Xp_cmdshell @cmd
    IF @retcode <> 0
      BEGIN
        SET @ReCopyTimes = @ReCopyTimes + 1
        UPDATE dbo.BackupFilelist
        SET    recopytimes = @reCopyTimes,Copy_status='F'
        WHERE  id = @id
        PRINT '时间:' + CAST(Getdate() AS VARCHAR) + ' 重新copy次数:' + CAST(@reCopyTimes AS VARCHAR)  --输出重试次数
        /*删除@netdevice映射*/
        SELECT @cmd = 'net use ' + @netdevice + ':' + ' /delete /y'
        EXEC master..Xp_cmdshell @cmd
        IF (@reCopyTimes < 5) --最多重试五次
          GOTO recopyflag
        ELSE --大于5次即五次copy都失败,则报错
          BEGIN
            SELECT @errorMessage = ' 自定义错误:' + @backup_path + ' 无法拷贝到' + @netdevice + Substring(@copy_path,2,Len(@copy_path))
            RAISERROR (@ErrorMessage,16,1)
            RETURN @retcode
          END
      END

    /*记录上传时间*/
    UPDATE dbo.BackupFilelist
    SET    Copy_end_time = Getdate(),Copy_status='T',ReCopyTimes=@ReCopyTimes
    WHERE  id = @id
 END
/*删除@netdevice映射*/
SELECT @cmd = 'net use ' + @netdevice + ':' + ' /delete  /y'
EXEC master..Xp_cmdshell @cmd

RETURN 0
复制代码

以上备份存储过程可执行三种类型备份FULL,LOG,DIFF;

1、在执行此存储过程之前,需要确认以上两个配置表是否已经建立。

2、存储过程内部调用spx_netuse;进行远程共享映射,具体原理如下章节(4.3、上传远程磁盘柜)

例如:添加sqlmonitor下configdb的备份;只备份到本地,不上传远程

复制代码
USE Configdb
GO
--插入配置信息
INSERT INTO [dbo].[BackupRestoreSetting](Servername,DBname,V_DBname,Backup_drive,Backup_path,Restore_drive,Restore_path,Copy_path,IsBackup,IsCopy)
VALUES('sqlmonitor','configdb','configdb','d','backup','d','sqldasta','m:\dbbackup\sqlmonitor','T','F')
GO
--完整备份:确认d:\backup目录是否存在
EXEC spx_Backup_DB @servername='sqlmonitor',@dbname='configdb',@backupset='FULL'
--差异备份
EXEC spx_Backup_DB @servername='sqlmonitor',@dbname='configdb',@backupset='DIFF'
--日志备份
EXEC spx_Backup_DB @servername='sqlmonitor',@dbname='configdb',@backupset='LOG'
复制代码

4.1、备份文件命名格式

数据库名称_备份时间_备份模式_数据库版本.BAK

例子:Configdb_20161009182755_LOG_P12.BAK

4.2、备份脚本解释

BACKUP DATABASE ['+@dbname+'] TO DISK ='''+@backup_path+ ''' WITH INIT,COMPRESSION

4.2.1、INIT

若已存在相同名称备份文件,覆盖该文件片;默认为追加NOINIT

4.2.2、COMPRESSION

压缩会消耗一定的io和cpu资源;相比压缩带来的好处,建议使用压缩备份。

好处:备份文件减少10倍;备份效率提高4倍,带宽压力减少。--2005版本不包括

4.2.3、加密

加密备份是非常有必要,但是SQL Server2012并没有提供备份加密,可用rar实行压缩加密等。此处不做赘述。

4.3、远程磁盘柜共享配置

远程磁盘柜的定义即为:某个服务器磁盘的共享文件夹,将文件夹设置为共享,语句某个账号读写,利用netuse 命令完成脚本映射后,即可通过cmd命令来完成脚本拷贝删除等命令。

4.3.1、共享文件夹设置

在磁盘柜上配置共享文件夹,例如:DBADataSource文件夹共享配置,允许BackupRestoreUser读写。

4.3.2、通过net use 命令映射

复制代码
--映射共享X: \\192.168.1.1\DBADataSource
EXEC master.dbo.xp_cmdshell 'net use x: \\192.168.1.1\DBADataSource "pwd" /user:"BackupRestoreUser"'    
--查询映射
EXEC master.dbo.xp_cmdshell 'net use'
复制代码

通过net use 完成映射磁盘,可供备份使用,封装成存储过程spx_netuse

复制代码
USE [Configdb]
GO

CREATE PROC [dbo].[spx_netuse]
          @drive CHAR(1)  OUTPUT,         
          @ip        VARCHAR(20),
          @directory VARCHAR(1000) = ''
WITH ENCRYPTION
AS

  DECLARE  @cmd VARCHAR(2000)
  DECLARE  @retcode int
  DECLARE  @netusetempdrives  TABLE(drive  CHAR(1),unused VARCHAR(100),status NVARCHAR(20))
  DECLARE  @netusetemp  TABLE(strs VARCHAR(2000))
  DECLARE  @errormessges VARCHAR(MAX)
  DECLARE  @unuseddrives TABLE(drive char(1))
  DECLARE @FLAG INT
  SET @FLAG = 0
  INSERT INTO @unuseddrives
  --排除ABCDEFG、Q
  SELECT  'I'
  UNION SELECT 'J'
  UNION SELECT 'K'
  UNION SELECT 'L'
  UNION SELECT 'M'
  UNION SELECT 'N'
  UNION SELECT 'O'
  UNION SELECT 'P'
  UNION SELECT 'R'
  UNION SELECT 'S'
  UNION SELECT 'T'
  UNION SELECT 'U'
  UNION SELECT 'V'
  UNION SELECT 'W'
  UNION SELECT 'X'
  UNION SELECT 'Y'
  UNION SELECT 'Z'

  IF @ip IS NULL  OR @ip NOT LIKE '%.%.%.%' OR @ip LIKE '%[a-Z]%'
    BEGIN
      SET @retcode =1000
      RAISERROR('NetUse IP IS Not Found',16,1) 
      RETURN @retcode
    END
  IF  @directory IS NOT NULL AND @directory<>''   AND Charindex(':\',@directory) > 1
    BEGIN
     SET @drive = LEFT(Ltrim(Rtrim(@directory)),1)
    END

  --本地使用的磁盘
  INSERT INTO @netusetempdrives (drive,unused)
  EXEC master.dbo.Xp_fixeddrives
  --已经映射的网络磁盘
  INSERT INTO @netusetemp(strs)
  EXEC master.dbo.Xp_cmdshell 'net use'
  --将所有已经被使用的磁盘汇总
  INSERT INTO @netusetempdrives (drive,status)
  SELECT Ltrim(Rtrim(Substring(strs,Charindex('   ',strs),Charindex(':',strs) - Charindex('   ',strs)))), Ltrim(Rtrim(LEFT(strs,10))) + '-netuse'
  FROM   @netusetemp
  WHERE  strs LIKE '%[a-Z]:%'

  --如果存在已经断开的映射,则删除磁盘
  IF EXISTS (SELECT TOP 1 1
             FROM   @netusetempdrives
             WHERE  drive = LEFT(Ltrim(Rtrim(@drive)),1)
                    AND status LIKE '%已断开-netuse%' AND status LIKE '%不可用-netuse%')
    BEGIN
      SELECT @cmd = 'master..xp_cmdshell ''net use ' + LEFT(Ltrim(Rtrim(@directory)),1) + ': /del'''
      EXEC @cmd

      DELETE FROM @netusetempdrives
      WHERE  drive = LEFT(Ltrim(Rtrim(@drive)),1) AND status LIKE '%已断开-netuse%' AND status LIKE '%不可用-netuse%'
    END

  DELETE FROM @unuseddrives
  WHERE drive IN (SELECT drive from @netusetempdrives)


  IF EXISTS (SELECT TOP 1 1
             FROM   @netusetempdrives
             WHERE  drive = LEFT(Ltrim(Rtrim(@drive)),1)
                    AND status NOT LIKE '%已断开-netuse%' and status NOT LIKE '%不可用-netuse%')  --磁盘已经被映射
     or @drive is null
    BEGIN
      IF NOT EXISTS (SELECT TOP 1 1 FROM @unuseddrives)
        BEGIN
          SET @retcode =3000
          --RAISERROR('不再有可映射磁盘!!!',16,1)
          RETURN @retcode
        END
      SELECT TOP 1  @drive = drive FROM @unuseddrives
      ORDER BY NEWID()
      DELETE  FROM @unuseddrives  WHERE drive =@drive
    END

    SELECT @cmd = 'net use ' + @drive + ': \\' + @ip + '\DBADataSource' + Substring(Ltrim(Rtrim(isnull(@directory,''))),3,Len(isnull(@directory,''))) + ' "pwd" /user:"BackupRestoreUser"'    

ReNetUse:--重复映射
       
    BEGIN TRY
      EXEC  @retcode = master..xp_cmdshell @cmd
    END TRY
    BEGIN CATCH
       SET @retcode = 4000

       IF  @FLAG = 0
       BEGIN
           WAITFOR DELAY '00:00:10'           
           SET @FLAG =1
           GOTO ReNetUse
       END
    END CATCH
 
  RETURN @retcode
复制代码

例如:

复制代码
--默认路径\\' + @ip + '\DBADataSource'
--映射:映射x :\\192.168.1.1\DBADataSource
exec [dbo].[spx_netuse] @drive='X',@ip='192.168.1.1'
--映射:映射x :\\192.168.1.1\DBADataSource;若x盘已经映射,则自动分配,并output 到@drive
declare @drive char(1)='X'
exec [dbo].[spx_netuse] @drive=@drive output,@ip='192.168.1.1'

--映射:映射x :\\192.168.1.1\DBADataSource\dbbackup;若x盘已经映射,则自动分配,并output 到@drive
exec [dbo].[spx_netuse] @drive='X',@ip='192.168.1.1',@directory='x:\dbbackup'
复制代码

五、spx_Backup_MoveFile归档历史备份

 默认情况下,建议所有备份上传到远程磁盘柜,而磁盘柜定义如上章节(4.4、上传远程磁盘柜)

与“本地备份删除”类似,建议归档在每次完整备份执行之前归档掉。

归档策略:

1、dbbackup文件夹:存放当前备份文件;由配置表BackupRestoreSetting的copy_path字段决定。

2、dbbackuphistory\2016\201610文件夹:保留每个数据库当月最早完整备份和所有日志备份

spx_Backup_MoveFile

六、自动化部署

策略制定:

  • 完整备份:每周一执行一次
  • 差异备份:每天执行一次,周一不执行
  • 日志备份:每1小时一次

6.1、新建配置表

BackupRestoreSetting

BackupFilelist

6.2、配置磁盘柜共享

若不上传远程,可排除远程共享配置;配置信息写入的时候设置isCopy=’F’即可

spx_netuse

6.3、新建存储过程

spx_Backup_DelFile

spx_Backup_DB

spx_Backup_MoveFile

以上存储过程为单个数据库的备份处理,自动化还需根据以上策略封装一层,方便Job调用和管理员维护。具体如下存储过程spb_Backup_DB

spb_Backup_DB

6.4、新建作业

6.4.1 完整差异备份

步骤一、spb_Backup_DB @servername='sqlmonitor',@backupset='FULL&DIFF'

执行计划、每天12点执行一次

6.4.2 日志备份

步骤一、spb_Backup_DB @servername='sqlmonitor',@backupset='LOG'

执行计划、每1小时执行一次

【7】我的最佳实践脚本

【7.1】脚本

CREATE PROCEDURE [dbo].[Generalization_Backup]  
 @Database_Name NVARCHAR(50),  --输入_备份数据库名称  
 @Bakup_Type INT,     --输入_备份类型:1完整备份,2差异备份,3事务日志  
 @Bakup_Folder NVARCHAR(200),  --输入_备份文件夹名  
 @Out_Message NVARCHAR(400) OUT  --输出_输出消息  
/*  
创建者:zachary  
创建时间:2011年6月24日  
功能说明:通用备份,输入备份数据库名称、备份类型、备份文件夹名就执行相应的备份操作  
*/  
AS  
BEGIN  
--==========创建需要的一些变量,拼接备份文件夹  
 DECLARE @Bakup_Path NVARCHAR(200), --备份路径  
   @SQL NVARCHAR(MAX),   --动态语句  
   @Day NCHAR(8),    --备份时间(年月日)  
   @Date NCHAR(11),   --备份时间(年月日_小时)  
   @Path NVARCHAR(200),  --备份路径  
   @Bakup_Name NVARCHAR(50) --备份文件名  
   
 DECLARE @t_driver TABLE (Driver CHAR(1),MB_Free INT) -- 该表变量保存各分区的剩余空间信息  
 INSERT INTO @t_driver EXEC master.dbo.xp_fixeddrives -- 填充分区剩余空间信息  
 SET @Bakup_Path = (SELECT MAX(Driver) FROM @t_driver WHERE Driver IN('C','D','E','F'))  
 SET @Bakup_Path = @Bakup_Path +':\'+@Bakup_Folder+'\'  
 --PRINT @Bakup_Path  
   
 EXEC MASTER.dbo.xp_create_subdir @Bakup_Path -- 创建备份文件夹  
   
 SET @Day=CONVERT(NCHAR(8),GETDATE(),112)  
 SET @Date=CONVERT(NCHAR(8),GETDATE(),112)+'_'+RIGHT(CONVERT(NCHAR(13),GETDATE(),120),2)  
 --PRINT @Day  
 --PRINT @Date  
--==========检查输入_备份数据库名称是否有效  
 IF NOT EXISTS(SELECT TOP 1 NULL FROM sys.databases WHERE NAME=@Database_Name)  
  BEGIN  
   SET @Out_Message='未找到名为'+@Database_Name+'的数据库,请检查输入数据库名'  
   RAISERROR (@Out_Message,16,1)  
   RETURN -1  
  END  
--==========检查输入_备份路径是否有效  
-- DECLARE @t1 TABLE(subdirectory NVARCHAR(100),depth INT) --该表变量保存输入文件夹下的所有文件夹名和文件名  
-- SET @Path=SUBSTRING(@Bakup_Path,1,LEN(@Bakup_Path)-LEN(@Bakup_Folder)-1)  
-- INSERT INTO @t1 EXEC xp_dirtree @Path,1  
-- IF @Bakup_Folder NOT IN (SELECT subdirectory FROM @t1)  
--  BEGIN  
--   SET @Out_Message='在路径'+@Path+'下找不到名为'+@Bakup_Folder+'的文件夹'  
--   RETURN -1  
--  END  
--==========检查磁盘空间是否足够,不足则删除  
 DECLARE @t2 TABLE(Disk_Name NCHAR(1),Disk_Size INT) --该表变量保存磁盘剩余空间  
 DECLARE @Database_Size INT,@Disk_Size INT  
 INSERT INTO @t2 EXEC xp_fixeddrives  
 SELECT @Disk_Size=Disk_Size FROM @t2 WHERE Disk_Name=SUBSTRING(@Bakup_Path,1,1)  
 DECLARE @sql1 NVARCHAR(2000)  
 SET @sql1='USE '+@Database_Name+'   
    SELECT @Database_Size=SUM(size/128) from sysfiles'  
 EXEC sp_executesql @sql1,N'@Database_Size INT OUTPUT',@Database_Size OUTPUT  
 IF @Disk_Size < (20480+@Database_Size) --剩余空间要大于20G+数据库所占大小之和  
  BEGIN  
   --SET @Out_Message='备份路径剩余空间小于数据库,不足以支持一次完整备份,请清理空间后再进行备份'  
   DECLARE @i INT   
   SET @i=30  
   WHILE @i>=3 --从30天开始循环删除备份文件,保留近3天的  
    BEGIN  
     DECLARE @Day1 NCHAR(8)   
     SET @Day1=CONVERT(NCHAR(8),GETDATE()-@i,112)  
     EXEC master.dbo.xp_delete_file 0,@Bakup_Path,'bak',@Day1  
     EXEC master.dbo.xp_delete_file 0,@Bakup_Path,'trn',@Day1  
     EXEC master.dbo.delete_file @i,@Bakup_Path  
     SET @i=@i-1  
     DECLARE @t3 TABLE (Disk_Name1 NCHAR(1),Disk_Size1 INT) --该表变量保存磁盘剩余空间  
     DECLARE @Database_Size1 INT,@Disk_Size1 INT  
     INSERT INTO @t3 EXEC xp_fixeddrives  
     SELECT @Disk_Size1=Disk_Size1 FROM @t3 WHERE Disk_Name1=SUBSTRING(@Bakup_Path,1,1)  
     EXEC sp_executesql @sql1,N'@Database_Size INT OUTPUT',@Database_Size1 OUTPUT  
     IF @Disk_Size1 > (20480+@Database_Size1)  
      SET @i=0 --一旦有足够的空间就停止循环  
    END  
  END  
--==========修改备份文件名  
 IF @Database_Name='Db_Tank'  
  SET @Bakup_Name=@Database_Name+'_Copy'  
 ELSE  
  SET @Bakup_Name=@Database_Name  
  
--==========完整备份  
 IF @Bakup_Type=1   
  BEGIN  
       
   BEGIN try  
    SET @SQL='BACKUP DATABASE ['+@Database_Name+'] TO DISK='''+@Bakup_Path+@Bakup_Name+CAST(DAY(GETDATE()) AS NVARCHAR(20))+'.bak'' WITH INIT,STATS = 10'  
    --PRINT @SQL  
    EXEC (@SQL)  
    SET @Out_Message='执行完整备份将数据库'+@Database_Name+'备份到'+@Bakup_Path+@Database_Name+CAST(DAY(GETDATE()) AS NVARCHAR(20))+'.bak'  
    PRINT @Out_Message  
    RETURN 0  
   END TRY  
   BEGIN CATCH   
    SET @Out_Message='系统输出了错误信息,错误信息为:'+ERROR_MESSAGE()+'错误号为:'+CAST(ERROR_NUMBER() AS NVARCHAR(10))+',执行失败!'  
    RAISERROR (@Out_Message,16,1)  
    RETURN -1  
   END CATCH   
  END   
--==========差异备份  
 IF @Bakup_Type=2   
  BEGIN  
   --==========判断数据库是否执行过完备  
   IF NOT EXISTS(SELECT TOP 1 NULL FROM msdb..backupset WHERE database_name=@Database_Name AND [type]='D')  
   BEGIN  
    SET @Out_Message='检查到数据库'+@Database_Name+'未执行过完整备份,不能进行差异备份'  
    RAISERROR (@Out_Message,16,1)  
    RETURN -1  
   END  
   BEGIN TRY   
    SET @SQL='BACKUP DATABASE ['+@Database_Name+'] TO DISK='''+@Bakup_Path+@Database_Name+'_'+@Date+'.bak'' WITH DIFFERENTIAL'  
    --PRINT @SQL  
    EXEC (@SQL)  
    SET @Out_Message='执行差异备份将数据库'+@Database_Name+'备份到'+@Bakup_Path+@Database_Name+'_'+@Date+'.bak'  
    PRINT @Out_Message  
    RETURN 0  
   END TRY   
   BEGIN CATCH   
    SET @Out_Message='系统输出了错误信息,错误信息为:'+ERROR_MESSAGE()+'错误号为:'+CAST(ERROR_NUMBER() AS NVARCHAR(10))+',执行失败!'  
    RAISERROR (@Out_Message,16,1)  
    RETURN -1  
   END CATCH   
  END  
--==========事务日志备份  
 IF @Bakup_Type=3   
  BEGIN  
   --==========判断数据库是否执行过完备  
   IF NOT EXISTS(SELECT TOP 1 NULL FROM msdb..backupset WHERE database_name=@Database_Name AND [type]='D')  
   BEGIN  
    SET @Out_Message='检查到数据库'+@Database_Name+'未执行过完整备份,不能进行事务日志备份'  
    RAISERROR (@Out_Message,16,1)  
    RETURN -1  
   END  
   BEGIN TRY  
    SET @SQL='BACKUP LOG ['++@Database_Name+'] TO DISK='''+@Bakup_Path+@Database_Name+'_'+@Date+'_log.trn'''  
    --PRINT @SQL  
    EXEC (@SQL)  
    SET @Out_Message='执行事务日志备份将数据库'+@Database_Name+'备份到'+@Bakup_Path+@Database_Name+'_'+@Date+'_log.trn'  
    PRINT @Out_Message  
    RETURN 0  
   END TRY  
   BEGIN CATCH  
    SET @Out_Message='系统输出了错误信息,错误信息为:'+ERROR_MESSAGE()+'错误号为:'+CAST(ERROR_NUMBER() AS NVARCHAR(10))+',执行失败!'  
    RAISERROR (@Out_Message,16,1)  
    RETURN -1  
   END CATCH  
  END  
 ELSE  
  BEGIN   
   SET @Out_Message='输入的备份类型'+CAST(@Bakup_Type AS NVARCHAR(10))+'错误,备份类型为:1完整备份,2差异备份,3事务日志'  
   RAISERROR (@Out_Message,16,1)  
   RETURN -1  
  END  
END  

【7.2】使用

--事务日志备份
DECLARE
@return_value int, @Out_Message nvarchar(400) EXEC @return_value = [dbo].[Generalization_Backup] @Database_Name = N'Db_Tank', @Bakup_Type = 3, @Bakup_Folder = N'Db_Tank_Back', @Out_Message = @Out_Message OUTPUT SELECT @Out_Message as N'@Out_Message' SELECT 'Return Value' = @return_value GO

 

 

 

支持原创,转载请注明出处!
http://www.cnblogs.com/chhuang/p/5977312.html

posted @ 2019-03-07 15:57  郭大侠1  阅读(510)  评论(0编辑  收藏  举报