SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑

SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑

关键词:CDC,数据库审计

详细参考:微软官网大神总结

原文:http://www.cnblogs.com/chenxizhang/archive/2011/08/10/2133408.html

SQL Server 2008中的CDC(Change Data Capture)功能使用及释疑

CDC(Change Data Capture:变更数据捕获)这个功能是SQL Server 2008企业版的功能,它提供了一种新的机制,对表格数据的更新进行跟踪,在数据仓库的建设过程中,通过这种技术,可以简化从业务数据库导入数据的复杂度。

之前我有过两篇文章介绍,最近因为又在和有关客户介绍这方面的应用。发现之前的例子不是那么完整和清楚,特此再整理一篇出来,给大家参考

一、什么是CDC?

变更数据捕获(Change Data Capture ,简称 CDC)记录 SQL Server 表的插入、更新和删除活动。SQLServer的操作会写日志,这也是CDC捕获数据的来源。

开启cdc的源表在插入、更新和删除活动时会插入数据到日志表中。cdc通过捕获进程将变更数据捕获到变更表中,通过cdc提供的查询函数,我们可以捕获这部分数据。

二、开启CDC

2.1、开启CDC的必要条件

  • sqlserver 2008 以上版本

  • 需要开启代理服务(作业)

  • 磁盘要有足够的空间,保存日志文件

  • 表必须要有主键或者是唯一索引

2.2、开启数据库CDC

1、 在需要开启cdc的数据库上执行脚本如下:

if exists(select 1 from sys.databases where name='db_name' and is_cdc_enabled=0)
begin
    exec sys.sp_cdc_enable_db
end

2、查询数据库的cdc开启状态

select is_cdc_enabled from sys.databases where name='db_name'

查询结果为“1”,表示开启成功。

2.3、开启表CDC

*注意:表中必须有主键或者唯一索引

1、添加次要数据文件组及文件

数据库右键“属性” >> “文件组”>> ”添加”

“文件” >> “添加”

2、执行以下脚本,开启表cdc

复制代码
--CDC是数据库文件组的名称
IF EXISTS(SELECT 1 FROM sys.tables WHERE name='table_name' AND is_tracked_by_cdc = 0)
BEGIN
    EXEC sys.sp_cdc_enable_table
        @source_schema = 'dbo', -- source_schema
        @source_name = 'table_name', -- table_name
        @capture_instance = NULL, -- capture_instance
        @supports_net_changes = 1, -- supports_net_changes
        @role_name = NULL, -- role_name
        @index_name = NULL, -- index_name
        @captured_column_list = NULL, -- captured_column_list
        @filegroup_name = 'CDC' -- filegroup_name
END
复制代码

3、查看表cdc开启状态

SELECT is_tracked_by_cdc FROM sys.tables WHERE name='table_name'

查询结果为“1”,表示开启成功。

三、使用CDC

开启cdc后会在数据库中生成以下文件,开启数据库GY_DB,开启表VW_GHZDK

下面我们会对部分表和函数进行说明

系统表:

cdc.change_tables:表开启cdc后会插入一条数据到这张表中,记录表一些基本信息

cdc.captured_columns:开启cdc后的表,会记录它们的字段信息到这张表中

cdc.VW_GHZDK_CT(cdc.表名_CT):记录VW_GHZDK表中所有变更的数据

字段“__$operation”为“1”代表删除,“2”代表插入,“3”执行更新操作前的值,“4”执行更新操作后的值。字段“__$start_lsn”由于更改是来源于数据库的事务日志,所以这里会保存其事务日志的开始序列号(LSN)

函数:

cdc.fn_cdc_get_all_changes_dbo_VW_GHZDK:针对在指定日志序列号 (LSN) 范围内应用到源表的每项更改均返回一行。如果源行在该间隔内有多项更改,则每项更改都会表示在返回的结果集中

cdc.fn_cdc_get_net_changes_dbo_VW_GHZDK:针对指定 LSN 范围内每个已更改的源行返回一个净更改行。也就是说,如果在 LSN 范围内源行具有多项更改,则该函数将返回反映该行最终内容的单一行

sys.fn_cdc_map_time_to_lsn:为指定的时间返回 cdc.lsn_time_mapping 系统表中 start_lsn 列中的日志序列号 (LSN) 值。可以使用此函数系统地将日期时间范围映射到基于 LSN 的范围,以供变更数据捕获枚举函数 cdc.fn_cdc_get_all_changes_<capture_instance> 和 cdc.fn_cdc_get_net_changes_<capture_instance> 返回此范围内的数据更改。

四、最佳实践:案例演示

-----------------------------------

1. 准备一个数据库,里面准备一个表,Orders

  image

2. 启用数据库级别的CDC选项

--在数据库级别启用CDC功能
EXEC sys.sp_cdc_enable_db 

这个命令执行完之后,会在系统表里面添加6个表格

    image

3.在需要做数据捕获的表上面启用CDC选项

EXEC sys.sp_cdc_enable_table 
  @source_schema='dbo',
  @source_name='Orders',
  @capture_instance='Orders',
  @supports_net_changes=0,
  @role_name=null

【备注】关于这个存储过程的具体用法和有关参数的含义,请参考

http://msdn.microsoft.com/en-us/library/bb522475.aspx

执行之后,会有如下的输出消息

image

这个提示的意思是说,要启动SQL Server Agent。因为CDC功能是要通过一个两个作业来自动化完成的

  image

与此同时,执行上面的命令还将在系统表中添加一个表格

  image

还会添加一个函数

  image

4.插入或者更新数据测试CDC功能

--插入或者更新数据测试CDC功能
INSERT Orders(CustomerID) VALUES('Microsoft');
INSERT Orders(CustomerID) VALUES('Google');

UPDATE Orders SET CustomerID='Yahoo' WHERE OrderID=1
DELETE FROM Orders WHERE OrderID=2

这个范例插入两行数据,紧接着又对第一行更新,然后还删除了第二行,所以最终只有一行数据

  image

那么,我们来看看CDC做了什么事情呢?

SELECT * FROM cdc.Orders_CT

  image

我们可以来解释一下上面结果的含义

__$operation=2的情况,表示新增

__$operation=3或者4,表示更新,3表示旧值,4表示新值

__$operation=1的情况,表示删除

很好理解,不是吗?

但是,我们一般都是需要按照时间范围进行检索,对吧,所以,需要使用下面的语法进行查询

--按照时间范围查询CDC结果
DECLARE @from_lsn BINARY(10),@end_lsn BINARY(10)
DECLARE @start_time DATETIME = '2011-8-10 00:00:00'
DECLARE @end_time DATETIME ='2011-8-11 00:00:00'
SELECT @from_lsn=sys.fn_cdc_map_time_to_lsn('smallest greater than or equal',@start_time)
SELECT @end_lsn=sys.fn_cdc_map_time_to_lsn(' largest less than or equal',@end_time)
SELECT * FROM cdc.fn_cdc_get_all_changes_Orders(@from_lsn,@end_lsn,'all')

关于sys.fn_cdc_map_time_to_lsn这个函数,请参考

http://msdn.microsoft.com/en-us/library/bb500137.aspx

查询的结果如下

image

如果需要包含更新操作的旧值,则可以以下的语法

DECLARE @from_lsn BINARY(10),@end_lsn BINARY(10)
DECLARE @start_time DATETIME = '2011-8-10 00:00:00'
DECLARE @end_time DATETIME ='2011-8-11 00:00:00'
SELECT @from_lsn=sys.fn_cdc_map_time_to_lsn('smallest greater than or equal',@start_time)
SELECT @end_lsn=sys.fn_cdc_map_time_to_lsn(' largest less than or equal',@end_time)
SELECT * FROM cdc.fn_cdc_get_all_changes_Orders(@from_lsn,@end_lsn,'all update old')

  image

通常,为了方便起见,我们会将这个查询定义为一个存储过程,如下

--定义存储过程来进行查询
CREATE PROC GetOrdersCDCResult(@start_time DATETIME,@end_time DATETIME)
AS
BEGIN
    DECLARE @from_lsn BINARY(10),@end_lsn BINARY(10)
    SELECT @from_lsn=sys.fn_cdc_map_time_to_lsn('smallest greater than or equal',@start_time)
    SELECT @end_lsn=sys.fn_cdc_map_time_to_lsn(' largest less than or equal',@end_time)
    SELECT * FROM cdc.fn_cdc_get_all_changes_Orders(@from_lsn,@end_lsn,'all')
END
 

然后,每次需要用的时候,就直接调用即可

--执行存储过程
EXEC GetOrdersCDCResult '2011-8-10','2011-8-11'

5.结合SSIS实现事实表的增量更新

下面展示了一个SSIS 包的设计,这里面读取CDC的数据,先进行一些查找,然后按照__$operation的值拆分成为三个操作,分别进行插入,更新和删除,这样就可以实现对事实表的增量更新

  image

本文所有的代码如下

USE SampleDatabase
GO

--在数据库级别启用CDC功能
EXEC sys.sp_cdc_enable_db 

--在需要做数据捕获的表格上面启用CDC功能
EXEC sys.sp_cdc_enable_table 
@source_schema='dbo',
@source_name='Orders',
@capture_instance='Orders',
@supports_net_changes=0,
@role_name=null --插入或者更新数据测试CDC功能 INSERT Orders(CustomerID) VALUES('Microsoft'); INSERT Orders(CustomerID) VALUES('Google'); UPDATE Orders SET CustomerID='Yahoo' WHERE OrderID=1 DELETE FROM Orders WHERE OrderID=2 --查询CDC的结果 SELECT * FROM cdc.Orders_CT --按照时间范围查询CDC结果 DECLARE @from_lsn BINARY(10),@end_lsn BINARY(10) DECLARE @start_time DATETIME = '2011-8-10 00:00:00' DECLARE @end_time DATETIME ='2011-8-11 00:00:00' SELECT @from_lsn=sys.fn_cdc_map_time_to_lsn('smallest greater than or equal',@start_time) SELECT @end_lsn=sys.fn_cdc_map_time_to_lsn(' largest less than or equal',@end_time) SELECT * FROM cdc.fn_cdc_get_all_changes_Orders(@from_lsn,@end_lsn,'all') --定义存储过程来进行查询 CREATE PROC GetOrdersCDCResult(@start_time DATETIME,@end_time DATETIME) AS BEGIN DECLARE @from_lsn BINARY(10),@end_lsn BINARY(10) SELECT @from_lsn=sys.fn_cdc_map_time_to_lsn('smallest greater than or equal',@start_time) SELECT @end_lsn=sys.fn_cdc_map_time_to_lsn(' largest less than or equal',@end_time) SELECT * FROM cdc.fn_cdc_get_all_changes_Orders(@from_lsn,@end_lsn,'all') END --执行存储过程 EXEC GetOrdersCDCResult '2011-8-10','2011-8-11'
原文地址:https://www.cnblogs.com/gered/p/10756397.html