SQL Server 2008新特性——更改跟踪

news2024/11/14 20:36:49

在大型的数据库应用中,经常会遇到部分数据的脱机和多个数据库的合并问题。比如现在有一个全省范围使用的应用程序,每个市都部署了单独的相同的应用程序服务器数据库服务器,每个月需要将全省所有市的数据全部汇总起来用于出全省的报表,这是一种很常见的数据库合并问题。再比如我们做了一个SmartClient的应用程序,每个客户端都有应用程序和数据库,另外还有一个中心数据库用于汇总所有客户端的数据。每个智能客户端上都可以对自己的数据库进行增删改查,一旦智能客户端连接到网络上时,系统就将客户端数据库中的数据更改全部应用到中心数据库中,这种偶尔连接的应用程序也是需要数据库的同步的。

对于前面说到的这些应用,最简单的同步方法就是删除原有数据,然后重新填充新的数据,对于小数据量的表来说这并没有什么问题,但是如果每个市都有几百万几千万条数据,那么要将省数据库中的数据删除了再把每个市中的数据全部填充到省数据库中显然是不可行的。这种情况下应该使用跟踪数据更改的方法,将每个市这个月的数据更改应用到省数据库中(感觉有点像是差异备份一样,只记录更改的)。在SQL Server 2008中提供了两种跟踪数据更改的方案:

变更数据捕获(Change Data Capture)

更改跟踪(Chang Tracking)

今天我主要说的是更改跟踪,变更数据捕获在以后进行讲解。

启用更改跟踪

更改跟踪是SQL Server 2008的一个新特性,默认情况下是没启用的。更改跟踪可以应用跟踪到具体一个数据库中的具体表甚至是具体的列。更改跟踪并不会创建触发器之类的对象,只是在用户对启用了更改跟踪的表进行了增加、修改和删除操作时,系统自动将该操作生成一个版本号,记录下操作的时间戳、操作的类型、受影响的数据的主键等信息。启用更改跟踪后对数据操作的性能影响不是很大。这些信息是记录到SQL Server系统表中的,系统自动负责清理和维护。

要使用更改跟踪需要启用数据库的更改跟踪功能和表的更改跟踪功能。在SSMS中数据库的属性窗口中可以启用数据库的更改跟踪:

这里将更改跟踪选项设置为true既可启用更改跟踪。另外3个选项就是跟踪的数据自动清理的开关和清理的时间,这个自动清理的时间必须大于我们要同步数据的周期,比如我们的数据是一个月同步一次,那么这个保持期就应该大于31天,如果设置保持期太短,那么我们的跟踪数据还没来得及同步就被自动清理了。

这里只是启用了数据库的更改跟踪,接下来是要启用表的更改跟踪。这里我们创建一个新的表t1并初始化几条数据:

CREATETABLEt1( 
    c1 INTIDENTITYPRIMARYKEY, 
    c2 VARCHAR(50)NOTNULL, 
    c3 DATETIMENOTNULL, 
    c4 VARCHAR(max))GOINSERTINTO t1 VALUES('test1','2009-1-1','www.cnblogs.com/studyzy')INSERTINTO t1 VALUES('test2','2009-1-1','www.cnblogs.com/studyzy')INSERTINTO t1 VALUES('test3','2009-1-2','www.cnblogs.com/studyzy')

复制

接下来在SSMS中查看表t1的属性窗口,可以在属性窗口中启用该表的更改跟踪功能:

其中第二个选项“跟踪已更新的列”是表示是否将更改跟踪细化到列上。对于一般的表来说,我们只需要知道具体哪些行进行了更改,然后在合并数据时将整行数据更新到中心数据库既可,但是如果表中有大对象列(text image varchar(max) varbinary(max) xml等数据类型的列)时,将整行进行更新可能非常慢,所以我们可以启用“跟踪已更新的列”将具体更新了哪些列记录下来,这样在合并数据时就直接更新这些列既可。

更改跟踪常用函数

在更改跟踪中最重要的一点就是版本号,版本号从0开始一直递增,对表的每一次更改操作都会产生一个新的版本号。使用

SELECTCHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('dbo.t1'))

复制

可以获得t1表最小版本号,由于是刚创建更改跟踪,所以这里返回的是0,如果我们进行了大量的操作以后,而且这些操作的时间已经超过了数据库更改跟踪中设置的保持期时间,那么过期的版本就会被系统自动清理,清理后最小版本就不是0了,而是保留的可用的最早版本。

SELECT CHANGE_TRACKING_CURRENT_VERSION()可以获得当前数据库的更改跟踪的最新版本。这里由于我们启用更改跟踪后还没有进行数据库操作,所以返回的也是0。

现在我们向表t1中插入一条数据,然后查看当前最新版本:

INSERTINTO t1 VALUES('test','2009-1-4','www.cnblogs.com/studyzy')SELECTCHANGE_TRACKING_CURRENT_VERSION()--返回1

复制

现在返回的版本号就是1了。

接下来我们再修改2条数据和删除1条数据,再查看版本号:

UPDATE t1 SET c3=GETDATE()WHERE c1<3--受影响2条数据 
DELETEFROM t1 WHERE c2='test3'--受影响1条数据 
SELECTCHANGE_TRACKING_CURRENT_VERSION()--返回3

复制

这里我们总共影响了4条数据,但是版本号为3说明版本号并不是以受影响的行实来定的,一次更新操作中不管影响了好多条数据(当然这里不能为0条)版本号只增加1。

现在版本号有了,接下来就是查询出这段时间t1的更改情况,需要使用表值函数:CHANGETABLE(CHANGES [要查询更改跟踪的表名], 从哪个版本开始的更改)。这里要查询t1表从0版本开始到现在的所有数据更改,那么对应的查询语句是:

SELECT*FROMCHANGETABLE(CHANGES dbo.t1,0)as ct

复制

系统返回结果:

SYS_CHANGE_VERSION

SYS_CHANGE_CREATION_VERSION

SYS_CHANGE_OPERATION

SYS_CHANGE_COLUMNS

SYS_CHANGE_CONTEXT

c1

2

NULL

U

0x0000000003000000

NULL

1

2

NULL

U

0x0000000003000000

NULL

2

3

NULL

D

NULL

NULL

3

1

1

I

NULL

NULL

4

这里每个列的数据类型、含义等在联机丛书里面解释的很清楚,我这里只简单介绍下返回的这个表:

在版本号为1的数据更改操作中是插入了一条数据,插入数据的主键c1=4;在版本号2的操作中更新了2条数据,分别是c1=1和c1=2的行;在版本3的操作中删除了c1=3的一条数据。

根据更改跟踪同步数据

现在所有的更改已经查询出来了,接下来就可以根据查询出来的这个结果同步数据了。为了演示方便,我这里将在同一个实例中建立TestDB1数据库并初始化t1表用于表示中心数据库。那么同步数据的操作应该是:

--首先将新增的数据插入到中心数据库中:
SETIDENTITY_INSERT TestDB1.dbo.t1 ONINSERTINTO TestDB1.dbo.t1(c1,c2,c3,c4)SELECT t1.*FROMCHANGETABLE(CHANGES dbo.t1,0)AS ct 
INNERJOIN t1 
ON ct.c1=t1.c1 
WHERE ct.SYS_CHANGE_OPERATION='I'--接下来将更改的数据应用到中心数据库中:
UPDATE TestDB1.dbo.t1 
SET c2=newt1.c2,c3=newt1.c3,c4=newt1.c4 
FROMCHANGETABLE(CHANGES dbo.t1,0)AS ct 
INNERJOIN dbo.t1 AS newt1 
ON ct.c1=newt1.c1 
WHERE ct.SYS_CHANGE_OPERATION='U'AND t1.c1=newt1.c1 

--将删除的数据从中心数据库删除:
DELETEFROM  TestDB1.dbo.t1 
WHERE c1 IN(SELECT c1 
            FROMCHANGETABLE(CHANGES dbo.t1,0)AS ct 
            WHERE ct.SYS_CHANGE_OPERATION='D')

复制

这样我们就使用更改跟踪实现了数据库的同步。该同步操作时的版本号是3,这个版本号必须要单独记下来,那么下次再进行同步是就从3开始查询。

通过更改跟踪更新列

前面的同步脚本中关于数据update操作是:

UPDATE TestDB1.dbo.t1 
SET c2=newt1.c2,c3=newt1.c3,c4=newt1.c4

复制

由于c4是大对象数据类型,如果里面存放了几十兆或者更大的数据,而实际上我们更新的并不是c4列,那么这种更新方式必然很浪费时间和资源。前面我们对t1表已经启用了“跟踪已更新的列”,那么就可以根据实际更新的列来更新数据。

使用CHANGE_TRACKING_IS_COLUMN_IN_MASK()函数可以判断一个列是否发生了更改,如果发生了更改则返回1,没有更改则返回0。比如查询c2是否发生更改:

SELECT*,CHANGE_TRACKING_IS_COLUMN_IN_MASK(COLUMNPROPERTY(OBJECT_ID('dbo.t1'),'c2','ColumnId'),SYS_CHANGE_COLUMNS)FROMCHANGETABLE(CHANGES dbo.t1,0)AS ct 
WHERE ct.SYS_CHANGE_OPERATION='U'

复制

这里返回0说明没有更改c2列,同样的方法可以判断出c3列发生了更改。

既然可以判断哪些列发生了更改,那么就可以根据发生更改的列来更新该列的数据,比如对于c2的更新语句就是:

UPDATE TestDB1.dbo.t1 
SET c2=newt1.c2 --更新c2列 
FROMCHANGETABLE(CHANGES dbo.t1,0)AS ct 
INNERJOIN dbo.t1 AS newt1 
ON ct.c1=newt1.c1 
WHERE ct.SYS_CHANGE_OPERATION='U'AND t1.c1=newt1.c1 
ANDCHANGE_TRACKING_IS_COLUMN_IN_MASK(COLUMNPROPERTY(OBJECT_ID('dbo.t1'),'c2','ColumnId'), ct.SYS_CHANGE_COLUMNS)=1--发生更改时才更新

复制

同样的方法可以写出c3列、c4列的更新语句。如果觉得这样重复的写很麻烦,那么可以写一个存储过程,传入列名,检查该列是否更改,如果更改了则更新。

总结

更改跟踪是在偶尔连接的数据库应用和同步数据时非常有用的一个特性。更改跟踪里面的核心就是版本号,每次在同步数据时记录下当前的版本号,下次再同步时CHANGETABLE函数就传入上次同步的版本号,这样可以避免重复同步。

更改跟踪的跟踪记录数据是保存到系统表中的,由系统来维护,在开启数据库的更改跟踪时可以设置自动清除的时间,从而保证系统不会因为记录太多的跟踪数据而导致数据库文件大小急剧膨胀。

更改跟踪启用后对一般的DML操作(增删改)是不会有影响的,所有的DML SQL语句照常使用,而且启用更改跟踪后并不会对系统性能造成明细影响。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/355486.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微搭使用笔记(三) 数据模型介绍及初步使用

基于数据模型实现表单页面的生成和数据的保存、查看 表单应用是微搭的一个重要的使用场景&#xff0c;我们举下面一个简单的问卷调查的例子: 基于以上问卷&#xff0c;本文我们采取数据模型的方式生成表单页面并完成数据的保存及查看。 数据模型概述 先看下官方文档对于数据…

使用 TypeScript 的 CheckJS 为你的陈旧 JavaScript 项目续命

&#x1f64b; Why CheckJS? 让 JavaScript 项目也能享受到 TS 的类型推导等诸多好处。* 和直迁 TypeScript 相比&#xff0c;大大降低成本和风险&#xff0c;例如&#xff1a;&#x1f6a5; 使用方法 安装依赖、追加配置 # 为你的项目安装 TypeScript npm install typescri…

冰蝎4.0特征分析及流量检测思路

0 1、 冰蝎4.0介绍 冰蝎是一款基于Java开发的动态加密通信流量的新型Webshell客户端。老牌Webshell管理神器——中国菜刀的攻击流量特征明显&#xff0c;容易被各类安全设备检测&#xff0c;实际场景中越来越少使用&#xff0c;加密 Webshell 正变得日趋流行。 由于通信流量被…

JAVA时间类及JAVA8新时间类

文章目录Java旧时间类关系图![在这里插入图片描述](https://img-blog.csdnimg.cn/e2c2c26c841e40bdb9cc85d0fc4bc1df.png)GMT、时间戳、统一标准时间、时区Java时间类创建时间类示例java.text.DateFormat时间格式转换java.util.Calendar总结Java时间类Java8新时间类InstantCloc…

Vulnhub-DC-2实战靶场

Vulnhub-DC-2实战靶场 https://blog.csdn.net/ierciyuan/article/details/127560871 这次试试DC-2&#xff0c;目标是找到官方设置的5个flag。 一. 环境搭建 1. 准备工具 虚拟机Kali&#xff1a; 自备&#xff0c;我的kali的IP为192.168.3.129 靶场机&#xff1a; https…

接口和抽象类

接口(Interface)和抽象类(Abstract Class)是支持抽象类定义的两种机制。 1.抽象类 (1)说明 在Java中被abstract关键字修饰的类称为抽象类&#xff0c;被abstract关键字修饰的方法称为抽象方法&#xff0c;抽象方法只有方法的声明&#xff0c;没有方法体。抽象类是用来捕捉子…

CCNP350-401学习笔记(151-200题)

151、Which two LISP infrastructure elements are needed to support LISP to non-LISP internetworking? (Choose two.)A. PETR B. PITRC. MR D. MS E. ALT 152、In an SD-WAN deployment, which action in the vSmart controller responsible for? A. handle, maintain, …

一文搞懂C/C++内存管理原理与实现

C 语言内存管理指对系统内存的分配、创建、使用这一系列操作。在内存管理中&#xff0c;由于是操作系统内存&#xff0c;使用不当会造成毕竟麻烦的结果。本文将从系统内存的分配、创建出发&#xff0c;并且使用例子来举例说明内存管理不当会出现的情况及解决办法。 一、内存 …

[python入门㊽] - 自定义异常 raise 关键字

目录 ❤ 自定义抛出异常关键字 - raise ❤ 使用raise主动引发异常 ❤ raise 关键字的用法 ❤ 触发异常 ❤ 自定义异常类 在前面我们学过异常三个关键字分别是try、except 以及 finally 在编程过程中合理的使用异常可以使得程序正常的执行。有直接抛出异常的形式&…

【HTML】HTML 表格总结 ★★★ ( 表格标签 | 行标签 | 单元格标签 | 表格标签属性 | 表头单元格标签 | 表格标题标签 | 合并单元格 )

文章目录一、表格标签组成 ( 表格标签 | 行标签 | 单元格标签 )二、table 表格属性 ( border 属性 | align 属性 | width 属性 | height 属性 )三、表头单元格标签四、表格标题标签五、合并单元格1、合并单元格方式2、合并单元格顺序3、合并单元格流程六、合并单元格示例1、原始…

Linux之ping\kill\killall命令

参考视频&#xff1a;linux命令&#xff08;ping&#xff09;linux命令&#xff08;kill、killall&#xff09;Linux ping 命令用于检测主机。执行 ping 指令会使用 ICMP 传输协议&#xff0c;发出要求回应的信息&#xff0c;若远端主机的网络功能没有问题&#xff0c;就会回应…

Redis进阶:布隆过滤器(Bloom Filter)及误判率数学推导

1 缘起 有一次偶然间听到有同事在说某个项目中使用了布隆过滤器&#xff0c; 哎呦&#xff0c;我去&#xff0c;我竟然不知道啥是布隆过滤器&#xff0c; 这我哪能忍&#xff1f;其实&#xff0c;也可以忍&#xff0c;但是&#xff0c;可能有的面试官不能忍&#xff01;&#…

简介JVM

目录 一、内存分区 1、程序计数器 2、栈 3、堆 4、方法区 二、类加载 1、Loading 2、Linking Verification Preparation Resolution 3、Initializing 4、双亲委派模型 三、垃圾回收 1、如何判断为垃圾&#xff1f; 引入引用计数 可达性分析 2、如…

Transformer论文阅读:Swin Transformer算法笔记

标题&#xff1a;Swin Transformer: Hierarchical Vision Transformer using Shifted Windows 会议&#xff1a;ICCV2021 论文地址&#xff1a;https://ieeexplore.ieee.org/document/9710580/ 官方代码&#xff1a;https://github.com/microsoft/Swin-Transformer 作者单位&am…

[安装之2] 台式计算机加固态硬盘,台式机添加固态硬盘教程_台式主机固态硬盘怎么安装

固态硬盘是用固态电子存储芯片阵列制成的硬盘&#xff0c;也是电脑中比较常见的内存硬件&#xff0c;有些用户在使用电脑时候&#xff0c;由于内存不足导致系统运行较卡的情况&#xff0c;往往会选择添加固态硬盘来解决&#xff0c;那么台式主机固态硬盘怎么安装呢&#xff1f;…

shell脚本内调用另外一个shell脚本的几种方法

有时会在一个shell脚本(如test_call_other_shell.sh)中调用另外一个shell脚本(如parameter_usage.sh)&#xff0c;这里总结几种可行的方法&#xff0c;这些方法在linux上和windows上(通过Git Bash)均适用&#xff1a; 1.通过source: 运行在相同的进程&#xff0c;在test_…

CCIE重认证-300-401-拖图题全

拖图 拖图题 编程 snippet&#xff1b;192.168.5.0&#xff0c;mask 255.255.255.0&#xff1b;number是192.168.5.0&#xff1b;mask是255.255.255.0 snippets&#xff1b;edit-config对config&#xff0c;loopback对name 100&#xff0c;address对primary&#xff0c;mask…

广度优先搜索算法 - 迷宫找路

广度优先搜索算法1 思考问题1.1 这个迷宫需不需要指定入口和出口&#xff1f;2 先粗略实现2.1 源码2.2 源码解释3 优化代码3.1 优化读取文件部分3.2 增加错误处理4 再优化-让程序变得更加灵活4.1 用户外部可以循环输入入口和出口5 完整代码这是一个提问者的提出的问题&#xff…

制造业的云ERP在外网怎么访问?内网服务器一步映射到公网

随着企业信息化、智能化时代的到来&#xff0c;很多制造业企业都在用云ERP。用友U 9cloud通过双版本公有云专属、私有云订阅、传统软件购买三种模式满足众多制造业企业的需求&#xff0c;成为一款适配中型及中大型制造业的云ERP&#xff0c;是企业数智制造的创新平台。 用友U 9…

python 面向对象利用selenium【获取某东商品信息】

用python程序和谷歌selenium插件获取某东商品详细信息【商品名称、商品简介&#xff0c;超链接】利用selenium自动化程序 中的css页面结构索取来获取详细数据关于谷歌selenium的安装方法和使用方法第一步检查自己谷歌浏览器的版本1.1 找到设置&#xff1a;并鼠标点击进入1.2进入…