一.需求背景

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

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

二.主要架构

三.主要关联表

2.1 归档基础配置表

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

CREATE TABLE [dbo].[DBData_ArchiveConfig](
[ID] [int] IDENTITY(1,1) NOT NULL,
[IP] [varchar](50) NULL,
[DBName] [varchar](50) NULL,
[DataTable] [varchar](50) NULL,
[TargetIP] [varchar](50) NULL,
[TargetDB] [varchar](50) NULL,
[TargetTable] [varchar](50) NULL,
[Prerequisite] [varchar](300) NULL,
[DelMaxQTY] [int] NULL,
[IsCheckOrderID] [int] NULL,
[SP_Name] [int] NULL,
[StartTime] [datetime] NULL,
[EndTime] [datetime] NULL
) ON [PRIMARY] GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Server IP(数据位于中央管理器中,所以归档数据库库所在的IP要维护,可维修虚拟的IP)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'IP'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'要归档的数据库' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'DBName'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'要归档的表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'DataTable'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备份指向的IP' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'TargetIP'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备份指向的数据库' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'TargetDB'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'备份指向的表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'TargetTable'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'归档条件' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'Prerequisite'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'循环中一次归档删除的数据量' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'DelMaxQTY'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'此为 备用字段,考虑可能有些表,会和其他表关联' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'IsCheckOrderID'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'为提高并发度,一个DB对应的归档SP可能是多个,通过此列,进行分组。' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'SP_Name'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'此为拓展字段,原计划根据 开始时间、结束时间,每天可以多个时间段内执行' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'StartTime'
GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'此为拓展字段,原计划根据 开始时间、结束时间,每天可以多个时间段内执行' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'DBData_ArchiveConfig', @level2type=N'COLUMN',@level2name=N'EndTime'
GO

2.2 归档运行的Log表

CREATE TABLE [dbo].[DBData_ArchiveLog](
[ID] [int] IDENTITY(1,1) NOT NULL,
[IP] [varchar](30) NULL,
[DBName] [varchar](30) NULL,
[DataTable] [varchar](80) NULL,
[BakQTY] [varchar](30) NULL,
[BakStartDate] [datetime] NULL,
[BakEndDate] [datetime] NULL
) ON [PRIMARY] GO

2.3 异常错误信息表

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

CREATE TABLE [dbo].[DBData_ArchiveErrLog](
[ID] [int] IDENTITY(1,1) NOT NULL,
[IP] [varchar](30) NULL,
[DBName] [varchar](60) NULL,
[DataTable] [varchar](80) NULL,
[TargetIP] [varchar](30) NULL,
[TargetDB] [varchar](60) NULL,
[TargetTable] [varchar](80) NULL,
[Errormsg] [nvarchar](max) NULL,
[TransDateTime] [varchar](30) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO

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

SET ANSI_NULLS ON
GO SET QUOTED_IDENTIFIER ON
GO -- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[SP_XXXXX_DataArchive]
AS
SET NOCOUNT ON; DECLARE @sql1 VARCHAR(MAX)
DECLARE @sql VARCHAR(MAX)
DECLARE @sql2 VARCHAR(MAX)
DECLARE @IP VARCHAR(MAX)
DECLARE @DBName VARCHAR(MAX)
DECLARE @DataTable VARCHAR(MAX)
DECLARE @TargetIP VARCHAR(MAX)
DECLARE @TargetDB VARCHAR(MAX)
DECLARE @TargetTable VARCHAR(MAX)
DECLARE @Prerequisite VARCHAR(MAX)
DECLARE @DelMaxQTY INT
DECLARE @StartTime DATETIME
DECLARE @EndTime DATETIME
DECLARE @qty INT
DECLARE @ISCHECKORDERID INT
----Carson 2018-12-17 备份数据的时间往往比删除的时间长3倍,因此,如果考虑将备份的操作转移到辅助库,将会对线上的操作影响降至更低
DECLARE @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 [中央管理器].[中央管理数据库].[dbo].[DBData_ArchiveConfig]
WHERE DataTable <> ''
AND TargetTable <> ''
AND DBNAME = 'XXXXXXXXX' and SP_Name='?????'
OPEN DBName
FETCH NEXT FROM DBName INTO @IP, @DBName, @DataTable, @TargetIP, @TargetDB,
@TargetTable, @Prerequisite, @DelMaxQTY, @ISCHECKORDERID,
@StartTime, @EndTime
WHILE ( @@fetch_status = 0 )
BEGIN
DECLARE @datetime DATETIME
IF @ISCHECKORDERID <> '' AND @DataTable <> ''
BEGIN
SET @datetime = CONVERT(VARCHAR(10), GETDATE() - 30, 120)
SET @sql = 'Insert into [' + @TargetIP + '].'
+ @TargetDB + '.' + 'dbo.' + @TargetTable + '
select * FROM ' + @BakDateIP + @DBName + '.' + 'dbo.' + @DataTable + '
with(nolock) where ' + @Prerequisite + '' SET @sql1 = 'DECLARE @icount INTEGER
SELECT @icount = COUNT(1)
FROM ' + @BakDateIP + @DBName + '.' + 'dbo.' + @DataTable + '
where ' + @Prerequisite + '
insert into [中央管理器].[中央管理数据库].dbo.DBData_ArchiveLog (IP, DBName, DataTable, BakQTY, BakStartDate, BakEndDate)
select ''' + @IP + ''',''' + @DBName + ''',''' + @DataTable
+ ''',@icount,getdate(),null WHILE @icount > 0
BEGIN DELETE TOP (' + CAST(@DelMaxQTY AS VARCHAR(10)) + ')
FROM ' + @DBName + '.' + 'dbo.' + @DataTable + '
where ' + @Prerequisite + ' SET @icount = @icount -('
+ CAST(@DelMaxQTY AS VARCHAR(10)) + ')
WAITFOR DELAY ''00:00:01''
END '
BEGIN TRY
EXEC (@sql)
EXEC (@sql1)
END TRY
BEGIN CATCH
DECLARE @Errmsg AS nvarchar(MAX)
SELECT @Errmsg=ERROR_MESSAGE()
------0001 BEGIN SAVE ERR LOG IN TABLE
INSERT INTO [中央管理器].[中央管理数据库].[dbo].DBData_ArchiveErrLog ([IP] ,[DBName],[DataTable],[TargetIP],[TargetDB],[TargetTable],[Errormsg] ,[TransDateTime])
VALUES(@IP, @DBName, @DataTable, @TargetIP, @TargetDB, @TargetTable,@Errmsg,convert(VARCHAR(25),GETDATE(), 120))
------0001 END
-------------0002 BEGIN SEND EMAIL MESSAGE----------------
DECLARE @Subject AS nvarchar(200)
DECLARE @Body AS nvarchar(MAX)
DECLARE @SPName AS nvarchar(MAX) SET @Subject = '数据库归档异常 -重要!;ServerIP:' + @IP + ' DB:' + @DBName
SET @SPName = ''
SET @Body = '<html><body>Dear All,<br> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServerIP:' +@IP + ' ; 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>'
SET @Body = @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 @SPName = @SPName + '<tr bgcolor=#ffaa11><td>'+ CAST(@IP AS NVARCHAR(50))+ '</td><td>' + CAST(@DBName AS NVARCHAR(50)) + '</td><td>'+CAST(@DataTable AS NVARCHAR(50))+ '</td>
<td>'+ CAST(@TargetIP AS NVARCHAR(20))+ '</td><td>'+ CAST(@TargetDB AS NVARCHAR(50))+ '</td><td>'+ SUBSTRING(@Errmsg,1, 100)+ '</td><td>'+ CONVERT(varchar(100), GETDATE(), 21)+ '</td></tr>'
SET @Body = @Body + @SPName + '</table>' SET @BODY=REPLACE(@BODY,'''','') IF REPLACE(@BODY,' ','')<>''
BEGIN
DECLARE @AllEmailToAddress varchar(3000)=''
DECLARE @AllEmailCcAddress varchar(3000)=''
DECLARE @Allprofile_name varchar(100)=''
SELECT @AllEmailToAddress=''
SELECT @AllEmailCcAddress=''
SELECT TOP 1 @Allprofile_name=NAME FROM msdb.dbo.sysmail_profile
ORDER BY profile_id EXEC msdb..sp_send_dbmail @profile_name = @Allprofile_name -- profile 名称
,@recipients = @AllEmailToAddress -- 收件人邮箱
,@copy_recipients=@AllEmailCcAddress
,@subject = @Subject -- 邮件标题
,@body = @BODY -- 邮件内容
,@body_format = 'HTML' -- 邮件格式
,@file_attachments=''
,@Importance = 'High'
END
------------- 0002 end ------------
END CATCH
END FETCH NEXT FROM DBName INTO @IP, @DBName, @DataTable, @TargetIP,
@TargetDB, @TargetTable, @Prerequisite, @DelMaxQTY,
@ISCHECKORDERID, @StartTime, @EndTime
END CLOSE DBName
DEALLOCATE DBName DECLARE DELETETABLE CURSOR
FOR
SELECT IP ,
DBName ,
DataTable ,
TargetTable ,
Prerequisite ,
DelMaxQTY
FROM [中央管理器].[中央管理数据库].[dbo].[DBData_ArchiveConfig]
WHERE DataTable <> ''
AND TargetTable = ''
AND DBNAME = 'XXXXXXXXX' and SP_Name='????'
OPEN DELETETABLE
FETCH NEXT FROM DELETETABLE INTO @IP, @DBName, @DataTable,
@TargetTable, @Prerequisite, @DelMaxQTY
WHILE ( @@fetch_status = 0 )
BEGIN
SET @sql1 = 'DECLARE @icount INTEGER
SELECT @icount = COUNT(1)
FROM ' + @DBName + '.' + 'dbo.' + @DataTable + '
where ' + @Prerequisite + '
WHILE @icount > 0
BEGIN DELETE TOP (' + CAST(@DelMaxQTY AS VARCHAR(10)) + ')
FROM ' + @DBName + '.' + 'dbo.' + @DataTable + '
where ' + @Prerequisite + ' SET @icount = @icount -('
+ CAST(@DelMaxQTY AS VARCHAR(10)) + ')
WAITFOR DELAY ''00:00:01''
END '
PRINT @sql1
EXEC (@sql1)
FETCH NEXT FROM DELETETABLE INTO @IP, @DBName, @DataTable,@TargetTable, @Prerequisite, @DelMaxQTY
END
CLOSE DELETETABLE
DEALLOCATE DELETETABLE GO

五.补充数据

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

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

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

关于SQL Server 数据库归档的一些思考和改进的更多相关文章

  1. 2014-07-30 MVC框架中对SQL Server数据库的访问

    今天是在吾索实习的第16天.我自己主要学习了基于MVC框架的系统的开发时,对SQL Server数据库的相关访问.其步骤如下: 第一步,在Models文件夹中创建一个类,并命名为Movies.cs,如 ...

  2. SQL Server数据库空间管理 (1)

    数据库经常遇到的问题: 1).数据库文件空间用尽  2).日志文件不停增长 3).数据库文件无法收缩  4).自动增长和自动收缩 本系列就以上面的4个问题入手分析并总结数据库空间的管理方法.   1. ...

  3. 2. SQL Server数据库状态监控 - 错误日志

    原文:2. SQL Server数据库状态监控 - 错误日志 无论是操作系统 (Unix 或者Windows),还是应用程序 (Web 服务,数据库系统等等) ,通常都有自身的日志机制,以便故障时追溯 ...

  4. 浅析SQL Server数据库中的伪列以及伪列的含义

    SQL Server中的伪列 下午看QQ群有人在讨论(非聚集)索引的存储,说,对于聚集索引表,非聚集索引存储的是索引键值+聚集索引键值:对于非聚集索引表,索引存储的是索引键值+RowId,这应该是一个 ...

  5. SQL Server 数据库表的管理

    上一篇文章简单梳理了一下SQL Server数据库的安装和基本操作,这篇文章主要讲述一下数据库表的管理 一.数据库的创建 有关数据库的创建有两种方式,一种是通过视图创建,第二种就是通过T-SQL语句来 ...

  6. SQL Server数据库文件与文件组总结

    文件和文件组概念 关于文件与文件组,简单概括如下,详情请参考官方文档"数据库文件和文件组Database Files and Filegroups"或更多相关资料: 数据文件概念: ...

  7. SQL Server数据归档的解决方案

    SQL Server数据归档的解决方案   最近新接到的一项工作是把SQL Server中保存了四五年的陈年数据(合同,付款,报销等等单据)进行归档,原因是每天的数据增量很大,而历史数据又不经常使用, ...

  8. .NET跨平台之旅:升级至ASP.NET 5 RC1,Linux上访问SQL Server数据库

    今天微软正式发布了ASP.NET 5 RC1(详见Announcing ASP.NET 5 Release Candidate 1),.NET跨平台迈出了关键一步. 紧跟这次RC1的发布,我们成功地将 ...

  9. SQL Server数据库定时自动备份

    SQL Server 数据库定时自动备份[转]   在SQL Server中出于数据安全的考虑,所以需要定期的备份数据库.而备份数据库一般又是在凌晨时间基本没有数据库操作的时候进行,所以我们不可能要求 ...

随机推荐

  1. css基础系列

    盒子模型 盒子模型的概念 高和宽的设置 边框的设置 内边距的设置 外边距的设置 盒子的计算 元素显示的方式 盒子模型: border边框,margin外边距,padding内部距,content内容, ...

  2. Android底部导航栏(可滑动)----TabLayout+viewPager

    [TabLayout] ①TabLayout是选项卡,在屏幕空间有限的情况下,对不同的空间进行分组.属于android support design,更多的用于新闻上,如果放在底部也可做底部导航栏 ② ...

  3. 从一个git仓库拷贝到另一个git仓库

    利用git从一个仓库拷贝一个项目到另一个仓库,并且log也能够一起过去. 1.从原地址克隆一份裸版本库,比如原本托管于 GitHub. git clone --bare http://github.. ...

  4. Sql Server 本地(客户端)连接服务器端操作

    网有很多相关内容,我在此做记录和总结 1.主要是sql server 配置管理工具的配置 在此参考 https://www.cnblogs.com/yougmi/p/4616273.html(再次感谢 ...

  5. ZJOI2019二轮游记

    Postscript 这个彩笔的省选随心游被中考实验考试坑掉了 所以前两天都一直脱离部队,第一天讲课完了才有的过去 一轮凉了那么二轮翻盘?翻车预定.之后还有上海的ACM没有CXR神仙的ACM窝怎么打啊 ...

  6. Spring Boot 面试,一个问题就干趴下了!

    最近栈长面试了不少人,其中不乏说对 Spring Boot 非常熟悉的,然后当我问到一些 Spring Boot 核心功能和原理的时候,没人能说得上来,或者说不到点上,可以说一个问题就问趴下了! 这是 ...

  7. 关于pip安装时提示"pkg_resources.DistributionNotFound"错误

    使用pip install --upgrade pip升级pip中途失败,再次安装pip,完成后出现如下错误: 尝试重新安装pip也不行,同样会出现上述问题. 此时我们查看/usr/bin/pip文件 ...

  8. Python爬虫入门教程 49-100 Appium安装+操作51JOB_APP(模拟手机操作之一)手机APP爬虫

    爬前准备工作 在开始安装Appium之前,你要先知道Appium是做什么的?Appium 是一个自动化测试开源工具,看到没,做测试用的,它有点类似Selenium,可以自动操作APP实现一系列的操作. ...

  9. 【Android Studio安装部署系列】三十二、Android模拟器Genymotion安装使用教程详解

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 一.注册\登录 打开Genymotion官网,https://www.genymotion.com/ ,首先点击右上角的Sign in进行 ...

  10. 利用Bootstrap Paginator插件和KnockoutJS完成分页功能

    在最近一个项目中,需要结合一堆条件查询并对查询的结果数据完成一个简单分页功能,可是做着做着,自己的思路越来越模糊,做到心态崩溃!!! 哈哈,特此花点时间重新总结,并从最简单的分页,然后向多条件查询分页 ...