SQL Server审计功能入门:CDC(Change Data Capture)
原文:SQL Server审计功能入门:CDC(Change Data Capture)
介绍
SQL Server 2008引入了CDC(Change Data Capture),它能记录:
1. 哪些数据行发生了改变
2. 数据行变更的历史记录,而不仅仅是最终值。
跟CT(Change Tracking)相比,它通过作业实现异步变更跟踪(像事务复制),而CT是同步实现的。因此它对性能的影响较轻并且不会影响事务。
典型应用是在提取、传输和加载数据到其它数据源,就像图中的数据仓库。

实现
微软建议CDC结合快照快照隔离级别使用,可以避免读取变更数据与变更数据写入时的读写阻塞。
需要注意:快照隔离级别会有额外的开销,特别是Tempdb(所有的数据更改都会被版本化存到tempdb)。
use master go create database CDCTest go alter database CDCTest set allow_snapshot_isolation on go --enable CDC on database CDCTest use CDCTest go exec sys.sp_cdc_enable_db go
启用CDC之后会新增一个叫CDC的Schema和一系列的系统表、SP和View。官方建议不要直接查询系统表而是使用对应的系统SP/FN来获取CDC数据。

| 
 系统对象  | 
 说明  | 
 建议使用的对象  | 
| 
 cdc.captured_columns  | 
 为在捕获实例中跟踪的每一列返回一行  | 
|
| 
 cdc.change_tables  | 
 为数据库中的每个更改表返回一行  | 
|
| 
 cdc.ddl_history  | 
 针对启用了变更数据捕获的表所做的每一数据定义语言 (DDL) 更改返回一行  | 
|
| 
 cdc.lsn_time_mapping  | 
 为每个在更改表中存在行的事务返回一行  | 
 sys.fn_cdc_map_lsn_to_time (Transact-SQL) , sys.fn_cdc_map_time_to_lsn (Transact-SQL)  | 
| 
 cdc.index_column  | 
 为与更改表关联的每一索引列返回一行  | 
|
| 
 msdb.dbo.cdc_jobs  | 
 存储用于捕获和清除作业的变更数据捕获配置参数  | 
 NA  | 
| 
 cdc.<capture_instance>_CT  | 
 对源表启用变更数据捕获时创建的更改表。 该表为对源表执行的每个插入和删除操作返回一行,为对源表执行的每个更新操作返回两行.capture_instance格式=SchameName_TableName  | 
创建测试表并对期启用CDC。使用sys.sp_cdc_enable_table 对表启用CDC。
--Create a test table for CDC
use CDCTest
GO
create table tb(ID int primary key ,name varchar(20),weight decimal(10,2));
go
EXECUTE sys.sp_cdc_enable_table
    @source_schema = N'dbo'
  , @source_name = N'tb'
  , @role_name = null;
GO
如果源表是数据库中第一个要启用变更数据捕获的表,并且数据库不存在事务发布,则 sys.sp_cdc_enable_table 还将为数据库创建捕获和清理作业。 它将 sys.tables 目录视图中的 is_tracked_by_cdc 列设置为 1。
对应的跟踪表cdc.dbo_tb_CT包含了源表所有的变更数据。它包含原来所有的列和5个新的列,结构如图:

验证
当在源表中操行数据更改操作,表cdc.dbo_tb_CT会记录下来。试一下:

为什么没有数据呢?因为之前介绍过了,CDC是靠作业来捕获变更数据的,我的Agent还没有运行。
手动启用后,就有数据了。

结果列的含义:
| 
 列名  | 
 数据类型  | 
 说明  | 
| 
 __$start_lsn  | 
 binary(10)  | 
 更改提交的LSN。在同一事务中提交的更改将共享同一个提交 LSN 值。  | 
| 
 __$seqval  | 
 binary(10)  | 
 一个事务内可能有多个更改发生,这个值用于对它们进行排序。  | 
| 
 __$operation  | 
 int  | 
 更改操作的类型: 1 = 删除 2 = 插入 3 = 更新(捕获的列值是执行更新操作前的值)。 4 = 更新(捕获的列值是执行更新操作后的值)。  | 
| 
 __$update_mask  | 
 varbinary(128)  | 
 位掩码,源表中被CDC跟踪的每一列对应一个位。如果 __$operation = 1 或 2,该值将所有已定义的位设置为 1。如果 __$operation = 3 或 4,则只有那些对应已更改列的位设置为 1。  | 
现在再插入一行,并更新它,然后再删除ID=1的行。再查看结果:

简单说明一下跟踪的查询结果:总共5行,第一行和第二行是插入数据,第三行和第四行是更新前后的数据,第五行是删除数据。操作类型由_$operation值可得知。
简单应用
前文中创建的tb表,记录了每个人的姓名和体重变化信息。另外某一个数据库(表tb_rs),它是体重变化趋势报表的数据源。它每天同步一次数据,更新自己的数据。怎么用CDC来实现这个需求呢?
CDC中记录了start_lsn,如果能知道tb_rs上次同步完成时,tb中被同步的最大LSN。那下次同步时,只需要同步tb表中大于此LSN的变更记录即可。
问题就简单:获取上次同步完成tb的最大LSN,获取大于此LSN的所有变更记录,更新tb_rs。
- 由sys.fn_cdc_map_time_to_lsn可以将时间映射到对应的LSN,时间就是前一天。
 - 由cdc.fn_cdc_get_net_changes_<capture_instance>能得到一天内的所有的净变更记录。
 - 由变更记录自定义同步逻辑和语句。
 
insert into tb
values(1,'Ken',70.2),(3,'Joe',66),(4,'Rose',50)
update tb
set weight=70
where ID=3;
delete from tb where name='Rose';
go
DECLARE @begin_time datetime, @end_time datetime, @begin_lsn binary(10), @end_lsn binary(10); 
--get the interval
select @begin_time=GETDATE()-1,@end_time=GETDATE();
--map the time to LSN of the CDC table tb
select  @begin_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time),
  @end_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
--get the net changes within the specified LSNs
SELECT * FROM cdc.fn_cdc_get_net_changes_dbo_tb(@begin_lsn, @end_lsn, 'all');

居然没有Rose的记录?Joe的信息被更新过,怎么才一条记录?
这是因为这里得到是净变更行,也就是最终结果的意思。新增然后又删除,不影响最终结果,所以没有。多次更新同一行的某一列数据,只返回最后更新的结果。
得到这个结果,我们就可以根据__$operation和实际数据定义同步数据的逻辑了。比如:
--generate sync statements
SELECT (case __$operation when 2 then 'insert into tb_rs values ('+cast(ID as varchar(2))+', '+Name+', '+cast(weight as varchar(10))+')'
        when 4 then 'update tb_rs set name='+name+',weight='+cast(weight as varchar(10))+' where ID='++cast(ID as varchar(2)) END)
FROM cdc.fn_cdc_get_net_changes_dbo_tb(@begin_lsn, @end_lsn, 'all');
对于更新过的行,同步数据时,我想要先判断出列是否被更改过和被更改的时间。更改过的列才需要被同步,而不是所有列同步一次。以name为例:
DECLARE @begin_time datetime, @end_time datetime, @begin_lsn binary(10), @end_lsn binary(10); 
--get the interval
select @begin_time=GETDATE()-1,@end_time=GETDATE();
--map the time to LSN of the CDC table tb
select  @begin_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time),
  @end_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
--get the all changes within the specified LSNs
SELECT *,
(Case sys.fn_cdc_has_column_changed('dbo_tb','name',__$update_mask) when 1 then 'Yes' when 0 then 'No' End) as isNameUpdated,
sys.fn_cdc_map_lsn_to_time(__$start_lsn) as updateTime
FROM cdc.fn_cdc_get_all_changes_dbo_tb(@begin_lsn, @end_lsn, 'all')
where __$operation in(3,4);
go
CDC不仅能记录DML操作,还能记录DDL操作。查询cdc.ddl_history。

但有一点要格外注意:新增的列,能被CDC DDL跟踪到,但是新列的数据变更却不能被CDC跟踪到。如果需要跟踪它,先禁用表上的CDC,再启用即可。
CDC Agent Job
在指定的数据库中首次启用CDC,并且不存在事务复制,则会创建capture和cleanup两个作业:

capture作业是用于扫描日志文件,把变更记录写到变更表中。调用sp_MScdc_capture_job来实现,可以根据当前库的实际事务吞吐量来设置扫描参数和扫描间隔,使得在性能开销和跟踪需求间达到合理平衡。
cleanup作业是清理变更变表中的数据,默认三天的数据。
所以合理设定cleanup的间隔是非常重要的。
这两个作业的相关的配置存储在msdb.dbo.cdc_jobs中。当前的默认配置如图:

 
总结
1. CDC使用方便,易于配置,能与同步抽取等应用结合使用。
2. CDC能满足大多数对数据审计的要求,但不能告诉你“谁”更改了数据。
3. 虽说CDC是异步的,对应性能影响小,但还是会增加开销,特别是IO读写和容量方面的。开启CDC,每次更改,都至少会额外增加一次数据文件写和日志文件写操作。
SQL Server审计功能入门:CDC(Change Data Capture)的更多相关文章
- SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑
		
SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑 关键词:CDC 原文:http://www.cnblogs.com/chenxizhang/arc ...
 - SQL Server审计功能入门:更改跟踪(Change Tracking)
		
原文:SQL Server审计功能入门:更改跟踪(Change Tracking) 介绍 更改跟踪是一种轻量型解决方案,它为应用程序提供了一种有效的更改跟踪机制.常规的,自定义变更跟踪和读取跟踪数据, ...
 - SQL Server审计功能入门:SQL Server审核 (SQL Server Audit)
		
原文:SQL Server审计功能入门:SQL Server审核 (SQL Server Audit) 介绍 Audit是SQL Server 2008之后才有的功能,它能告诉你"谁什么时候 ...
 - Oracle CDC (Change Data Capture)更新数据捕获——概述
		
Change Data Capture能高效识别并捕获数据的插入.修改和删除,使更新数据供个人或应用使用. CDC从oracle 9i开始引入,//TODO 在11G R2之后的版本里将取消支持,被O ...
 - Oracle CDC (Change Data Capture)更新数据捕获——Asynchronous HotLog Mode(附带简单的kettle任务实现数据同步)
		
Performing Asynchronous HotLog Publishing Step 1 Source Database DBA: Set the database initializat ...
 - SSIS CDC(Change Data Capture)组件在数据库中启用报错。  The error returned was 14234: 'The specified '@server' is invalid
		
昨天实验CDC,在数据库中执行以下语句的时候出错. EXEC sys.sp_cdc_enable_table @source_schema = N'stg', @source_name = N'CDC ...
 - SQL Server 变更数据捕获(CDC)
		
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/字段/对象更改 概述 变更数据捕获用于捕获应用到 SQL Server 表中的插入.更新和删除活动,并以易于使用的关系格式提供这些 ...
 - 在SQL Server 2012中实现CDC for Oracle
		
在上篇在SSIS 2012中使用CDC(数据变更捕获)中,介绍了如何在SSIS 2012中使用CDC,本文在此基础上介绍,如何通过Attunity提供的Change Data Capture Desi ...
 - 腾讯云数据库团队:SQL Server 数据加密功能解析
		
数据加密是数据库被破解.物理介质被盗.备份被窃取的最后一道防线:数据加密,一方面解决数据被窃取安全问题,另一方面有关法律要求强制加密数据:SQL Server 的数据加密相较于其他数据库,功能相对完善 ...
 
随机推荐
- jquery 弹出登陆框,简单易懂!修改密码效果代码
			
在网上找了一大堆,看的眼花瞭乱,还是研究原码,自已搞出来了! ui原地址:http://jqueryui.com/dialog/#modal-form 可以把js,css下载到本地,要不然不联网的话, ...
 - 搭建ganglia集群而且监视hadoop CDH4.6
			
前言 近期在研究云监控的相关工具,感觉ganglia颇有亮点,能从一个集群总体的角度来展现数据. 但是安装过程稍过复杂,相关依赖稍多,故写此文章与大家分享下. 本文不解说相关原理,若想了解请參考其它资 ...
 - POJThe Doors AND NYIST 有趣的问题
			
POJThe Doors AND NYIST 有趣的问题 题目链接:pid=227" target="_blank">Click Here~ 题目分析: 给你横纵坐 ...
 - Web测试基于实际测试的功能测试点总结--转载
			
文章来源:http://www.51testing.com/html/99/n-854599.html 好文章就该记录一下\(^o^)/~ 一.页面链接检查:测试每一个链接是否都有对应的页面,并且页面 ...
 - C++传递函数指针
			
函数指针是一个很好的类型.因此,您可以编写一个函数,它的一个参数是一个函数指针.然后.在(外部)当函数使用的函数指针参数,来间接调用时调用相应的参数的函数的函数. 因为指针在不同的情况下能够指向不同的 ...
 - Openfire开发配置,Openfire源码配置,OpenFire二次开发配置
			
1.下载源码:http://www.igniterealtime.org/downloads/source.jsp 2.把源码解压出的openfire_src目录放至eclipse workplace ...
 - 怎么样excel其产生的条形码(10分钟的时间excel)从而出现了条形码
			
现在快递行业.京东购物,这样一来,使用条码管理,因此,如何在你的excel其中还生产商品条码管理它?其实很easy,4步骤学会!10分钟搞定. 1.从网址如下.下载字体, 2.双击安装字体. 3,在e ...
 - 协同编辑多人word一个小技巧文件
			
协同编辑多人word窍门 近期在工作中编写标书时因为不同内容分给了各个部门去制作.可是在汇总后遇到再次改动的问题.对方把改动后的部分文档发给我粘贴到标书中后,所有的格式所有都乱了.又一次整理格式.标题 ...
 - WPF中的三维空间(1)
			
原文:WPF中的三维空间(1) WPF中可以创建三维几何图形,支持3D对象的应用,支持从3D Max等软件将3D文件obj导入设计中,但是目前还不支持将材质同时导入,这样需要在WPF中对3D对象重新设 ...
 - c++  primer 函数传值1
			
不看c++ primer 永远不知道自己基础有多差 函数的參数传值一般有两种方式:值传递,引用传递. 值传递有以下两种形式: void func( int a ) { // } void func1 ...