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


为在捕获实例中跟踪的每一列返回一行


sys.sp_cdc_get_source_columns


cdc.change_tables


为数据库中的每个更改表返回一行


sys.sp_cdc_help_change_data_capture


cdc.ddl_history


针对启用了变更数据捕获的表所做的每一数据定义语言 (DDL) 更改返回一行


sys.sp_cdc_get_ddl_history


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


为与更改表关联的每一索引列返回一行


sys.sp_cdc_help_change_data_capture


msdb.dbo.cdc_jobs


存储用于捕获和清除作业的变更数据捕获配置参数


NA


cdc.<capture_instance>_CT


对源表启用变更数据捕获时创建的更改表。 该表为对源表执行的每个插入和删除操作返回一行,为对源表执行的每个更新操作返回两行.capture_instance格式=SchameName_TableName


cdc.fn_cdc_get_all_changes_<capture_instance> ,

cdc.fn_cdc_get_net_changes_<capture_instance>

创建测试表并对期启用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。

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,每次更改,都至少会额外增加一次数据文件写和日志文件写操作。

时间: 2024-08-30 01:36:54

SQL Server审计功能入门:CDC(Change Data Capture)的相关文章

SQL Server审计功能入门:更改跟踪(Change Tracking)

原文:SQL Server审计功能入门:更改跟踪(Change Tracking) 介绍        更改跟踪是一种轻量型解决方案,它为应用程序提供了一种有效的更改跟踪机制.常规的,自定义变更跟踪和读取跟踪数据,会使用触发器,存储过程和记录变更的用户表等, 还需要保证访问一致和相关清理工作. 使用CT会减少额外工作量和保证访问一致性. 启用CT的表上必须得有主键,所有版本适用.为了保证更改信息的有效性,官方建议结合快照隔离使用. CT只能提供:                     哪些行/

SQL Server审计功能入门:SQL Server审核 (SQL Server Audit)

原文:SQL Server审计功能入门:SQL Server审核 (SQL Server Audit) 介绍     Audit是SQL Server 2008之后才有的功能,它能告诉你"谁什么时候做了什么事情".具体是指审核SQL Server 数据库引擎实例或单独的数据库涉及到跟踪和记录数据库引擎中发生的事件.它的底层是基于扩展事件(Extented Event),所以其性能和灵活性相对较好.审核数据可以输出到审核文件.Windows安全日志和应用程序日志.     Audit都需

Introduction to Change Data Capture (CDC) in SQL Server 2008[转]

Change Data Capture records INSERTs, UPDATEs, and DELETEs applied to SQL Server tables, and makes a record available of what changed, where, and when, in simple relational 'change tables' rather than in an esoteric chopped salad of XML. These change

浅析SQL 2008的Change Data Capture功能

在常见的企业数据平台管理中有一项任务是一直困扰SQL Server DBA们的,这就是对数据更新的监控.很多数 据应用都需要捕获对业务数据表的更新.笔者见过几种解决方案: 1.在数据表中加入特殊的标志列: 2. 通过在数据表上创建触发器: 3.通过第三方产品,例如Lumigent的Log Explorer. 其实第1种和第2中方案都不好,因为第1种方法需要在应用程序编码的时候尤为小心,如果有一段数据访问逻辑 忘了更新标志位就会导致遗漏某些数据更新,而第2种方法对性能影响过于明显,因为触发器的性能

用COM自动服务扩展SQL Server的功能

server     SQL Server的T-SQL编程语言在数据存储和恢复方面功能强大,但在与SQL Server数据库之外的系统交互方面则功能较弱.然而,我们可以通过SQL Server内置的COM自动操作环境来克服这个限制,SQL Server内置的COM自动操作环境可以使用户在存储过程中自动操作COM对象. 在SQL Server 7.0和SQL Server 6.5中提供了7个扩展的存储过程,可以通过自己开发的或Office等现成的COM对象扩展SQL Server的功能.SQL S

SQL Server时间戳功能与用法详解

本文实例讲述了SQL Server时间戳功能与用法.分享给大家供大家参考,具体如下: 一直对时间戳这个概念比较模糊,相信有很多朋友也都会误认为:时间戳是一个时间字段,每次增加数据时,填入当前的时间值.其实这误导了很多朋友. 1.基本概念 时间戳:数据库中自动生成的唯一二进制数字,与时间和日期无关的, 通常用作给表行加版本戳的机制.存储大小为 8个字节. 每个数据库都有一个计数器,当对数据库中包含 timestamp 列的表执行插入或更新操作时,该计数器值就会增加.该计数器是数据库时间戳.这 可以

SQL Server时间戳功能与用法详解_MsSql

本文实例讲述了SQL Server时间戳功能与用法.分享给大家供大家参考,具体如下: 一直对时间戳这个概念比较模糊,相信有很多朋友也都会误认为:时间戳是一个时间字段,每次增加数据时,填入当前的时间值.其实这误导了很多朋友. 1.基本概念 时间戳:数据库中自动生成的唯一二进制数字,与时间和日期无关的, 通常用作给表行加版本戳的机制.存储大小为 8个字节. 每个数据库都有一个计数器,当对数据库中包含 timestamp 列的表执行插入或更新操作时,该计数器值就会增加.该计数器是数据库时间戳.这 可以

基于IBM InfoSphere DataStage和IBM InfoSphere Change Data Capture集成的解决方案

传统上,通过在非操作时间段内使用一个 ETL 流程批量处理,每年.每月或每周对http://www.aliyun.com/zixun/aggregation/8302.html">数据仓库更新一次.在今天的业务环境中,一线业务用户需要根据每小时.每分钟甚至每秒更新的信息制定决策.这些实时数据需求使得批处理窗口萎缩,并需要一个高效的解决方案来解决这个问题. IBM InfoSphere DataStage 和 IBM InfoSphere Change Data Capture 的集成是通过

实例讲解SQL Server加密功能_MsSql

SQL Server中加密是层级的,每一个上层为下提供保护.如图: 实例:/** SMK(Service Master Key)在SQL Server安装时生成,由Windows DPAPI(Data Protection API)提供保护 **/ /**创建数据库级别DMK(Database Master Key),受SMK保护**/ create master key encryption by password=N'Passw0rd' go /**数据库内的加密对象受DMK保护 支持的对称