关于SQL Server 数据库归档的一些思考和改进

一.需求背景

SQL Server开源的归档工具不多,DBA一般都是通过计划任务来触发执行,执行的脚本多是SP或者是SSIS包。SSIS包的性能稍好一些,但是维护更新成本高些。所以更常见的是通过SP脚本来实现归档操作。

当数据库规模较小时,可以方便的直接在数据库上进行脚本的编写部署。但是随着数据库越来越多,管理维护成本就会越来越大,越来越不方便。现在我们实行的方式是通过中央管理器来管理众多的数据库备份(这是在拥有专门的备份程序前的一个过渡方案)。我们将归档基础配置信息、归档运行历史记录、异常报错等数据统一维护在中央数据库上。如此,可以方便统一的查看、管理和维护。

 二.主要架构

 

三.主要关联表

2.1 归档基础配置表

表字段含义,请耐心查看字段说明。

CREATE TABLE [dbo].DBData_ArchiveConfig](
    ID] intIDENTITY(1,1) NOT NULL,IPvarchar](50) DBNameDataTableTargetIPTargetDBTargetTablePrerequisite300) DelMaxQTY] IsCheckOrderIDSP_NameStartTimedatetimeEndTime
) ON PRIMARY]

GO

EXEC sys.sp_addextendedproperty @name=N'MS_Description',@valueServer IP(数据位于中央管理器中,所以归档数据库库所在的IP要维护,可维修虚拟的IP)@level0typeSCHEMA@level0name@level1typeTABLE@level1name@level2typeCOLUMN@level2name'
要归档的数据库要归档的表备份指向的IP备份指向的数据库备份指向的表归档条件循环中一次归档删除的数据量此为 备用字段,考虑可能有些表,会和其他表关联为提高并发度,一个DB对应的归档SP可能是多个,通过此列,进行分组。此为拓展字段,原计划根据 开始时间、结束时间,每天可以多个时间段内执行GO

2.2 归档运行的Log表

DBData_ArchiveLog30) 80) BakQTYBakStartDateBakEndDateGO

2.3 异常错误信息表

执行的过程中会外包一层 try...catch,将操作过程中的错误信息保存在表 DBData_ArchiveErrLog。表结构如下:

DBData_ArchiveErrLog60) Errormsgnvarchar](max) TransDateTime] TEXTIMAGE_ON GO

四. 存储过程相应的主要代码

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER -- =============================================
-- Author:        <Author,Name> Create date: <Create Date,> Description:    <Description,1)"> =============================================
PROCEDURE SP_XXXXX_DataArchive]
AS
    SET NOCOUNT ON;

    DECLARE @sql1 VARCHAR(MAX) 
    @sql @sql2 )
    @IP @DBName @DataTable @TargetIP @TargetDB @TargetTable @Prerequisite @DelMaxQTY INT
    @StartTime DATETIME
    @EndTime @qty INT 
    @ISCHECKORDERID INT 
--Carson   2018-12-17 备份数据的时间往往比删除的时间长3倍,因此,如果考虑将备份的操作转移到辅助库,将会对线上的操作影响降至更低
    @BakDateIP VARCHAR(30)  
    set @BakDateIP=[XXX.XXX.XXX.XXX].'-----后面一定要有一个点------------------------------------------------归档操作---------------------------------
    DECLARE DBName CURSOR
    FOR
        SELECT  IP,DBName,DataTable,TargetIP,TargetDB,TargetTable,Prerequisite,DelMaxQTY,ISCHECKORDERID,StartTime,EndTime
        FROM    中央管理器中央管理数据库]
        WHERE   DataTable <> ''
                AND TargetTable AND DBNAME = XXXXXXXXX' and SP_Name?????'
    OPEN DBName    
    FETCH NEXT FROM DBName INTO @IP,1)">@DBName,1)">@DataTable,1)">@TargetIP,1)">@TargetDB@TargetTable,1)">@Prerequisite,1)">@DelMaxQTY,1)">@ISCHECKORDERID@StartTime,1)">@EndTime   
    WHILE ( @@fetch_status = 0 )
    BEGIN  
        @datetime DATETIME
        IF @ISCHECKORDERID 1'  AND @DataTable ''
        BEGIN
            SET @datetime CONVERT(10),GETDATE() - 30,1); font-weight: bold">120)                
            @sql Insert into [+ @TargetIP + ].'
                @TargetDB .dbo.@TargetTable 
                 select * FROM @BakDateIP @DBName  
                 with(nolock) where @Prerequisite ''
                
            @sql1 DECLARE @icount INTEGER  
                        SELECT @icount = COUNT(1)  
                        FROM 
                        where   
                        insert into [中央管理器].[中央管理数据库].dbo.DBData_ArchiveLog (IP,BakQTY,BakStartDate,BakEndDate)
                        select ''' @IP '''@DataTable
                                    CAST(AS 10)) )  
                            FROM  
                            where 
      
                            SET @icount = @icount -('
                                    )  
                            WAITFOR DELAY ''00:00:01  
                        END  '                    
          BEGIN TRY
            EXEC (@sql)
            @sql1) 
          END TRY
           CATCH
             @Errmsg nvarchar()
             SELECT @Errmsg=ERROR_MESSAGE()
               ----0001 BEGIN SAVE ERR LOG IN TABLE
               INSERT INTO ].DBData_ArchiveErrLog  (],1)">)
               VALUES(@TargetDB,1)">@Errmsg,1)">convert(25),1)">GETDATE(),1)">))       
               ----0001 END
                -----------0002 BEGIN SEND EMAIL MESSAGE----------------              
                    @Subject nvarchar(200)
                    @Body @SPName )
            
                    @Subject 数据库归档异常 -重要!;ServerIP: DB:@DBName
                                @SPName ''
                                @Body <html><body>Dear All,<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServerIP:+ ; DataBase:@DBName上的Table归档异常,请及时检查!!!
                               <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;You can get detail information from the table. <br><br><table border=1 bgcolor=#aaff11>' 
                                = @Body<tr bgcolor=#ff3311><td>ServerIP</td><td>DBName</td><td>TableName</td><td>TargetIP</td><td>TargetDB</td><td>Errmsg</td><td>TransDateTime</td></tr>'
                                SELECT  <tr bgcolor=#ffaa11><td>'NVARCHAR(50))</td><td>50)) +</td>
                                <td>20))SUBSTRING(100)varchar(100),1); font-weight: bold">21)</td></tr></table>'

                    @BODYREPLACE(@BODY,1)">'''',1)">'')

                    IF ' '')<>''
                        BEGIN
                            @AllEmailToAddress 3000)''
                            @AllEmailCcAddress @Allprofile_name @AllEmailToAddress@AllEmailCcAddressTOP 1 @Allprofile_name=NAME FROM msdb.dbo.sysmail_profile 
                            ORDER BY profile_id

                            EXEC msdb..sp_send_dbmail @profile_name @Allprofile_name    profile 名称 ,1)">@recipients   =  @AllEmailToAddress         收件人邮箱 ,1)">@copy_recipients@AllEmailCcAddress@subject      @Subject                   邮件标题 ,1)">@body         @BODY                      邮件内容 ,1)">@body_format  =  HTML'                     邮件格式 ,1)">@file_attachments@Importance High'
                        END     
                      -----------    0002 end ------------            
              CATCH          
            END

                @TargetIP@DelMaxQTY@ISCHECKORDERID,1)">@EndTime      
        END
        
    CLOSE DBName 
    DEALLOCATE DBName

    DECLARE DELETETABLE ???? DELETETABLE  
    FROM DELETETABLE @DataTable@DelMaxQTY
     )
        BEGIN
          DECLARE @icount INTEGER  
                                    SELECT @icount = COUNT(1)  
                                    FROM 
                                    where   
                                    WHILE @icount > 0   
                                    BEGIN  
                    
                                        DELETE TOP ()  
                                        FROM  
                                        where 
      
                                        SET @icount = @icount -('
                                                )  
                                        WAITFOR DELAY   
                                    END  PRINT @sql1
                        @DelMaxQTY
        END 
     DELETETABLE 
     DELETETABLE

GO

五.补充数据

1.数据库归档,一般都是先将当前库的历史数据归档到历史库,再将当前库的历史数据删除。这两个阶段,一般是前者耗时较多(一般都在2:1以上),虽然可以在select 过程加上nolock,但是或者I/O或者网络等原因,其实这个阶段对应用程序的影响还是比较大的。所以,建议将这两个阶段物理分开,即如果有配置AlwaysOn,请将第一个阶段在辅助数据库中执行。上面的SP示例,就是通过参数 @BakDateIP 来实现了这一作用。

2.存储过程中包含了try...catch,所以运行此sp就会很少报错,某一个表的异常不会相互影响。例如,我们常见的当前库、历史库由于表结构变更而导致的不一致,此情况出现后,try..catch可以捕捉到异常,将异常记录在档,并将此信息以邮件的形式发送给指定人,但整个SP不会执行失败。并且还会跳过这一个异常,继续执行下一个备份归档表的归档。

 

本文版权归作者所有,未经作者同意不得转载,谢谢配合!!!

相关文章

本篇内容主要讲解“sqlalchemy的常用数据类型怎么使用”,感...
今天小编给大家分享一下sqlServer实现分页查询的方式有哪些的...
这篇文章主要介绍“sqlmap之osshell怎么使用”,在日常操作中...
本篇内容介绍了“SQL注入的知识点有哪些”的有关知识,在实际...
1. mssql权限sa权限:数据库操作,文件管理,命令执行,注册...
sql执行计划如何查看?在SPL庞大的数据中我们不知道如何查看...