以下材料搜集、整理均由书婷完成。
============================================================================================
SQL Server中记录数据变更的四个方法:触发器、Output子句、变更数据捕获(ChangeData Capture )功能、同步更改跟踪。其中后两个为SQLServer 2008所新增。
如果要记录某个表或视图的Insert/Update/Delete操作,我们可以借助触发器 这在数据量较小的情况下往往是有效的方式之一,其中后触发器(After Trigger)只能跟踪表的三个操作中的任意组合,而前触发器(InsteadOf trigger)可以处理表和视图的更新。
触发器的缺点:
1、触发器通常很隐蔽,换句话说,易忘记,特别在检查性能和逻辑问题时。
2、长时间运行的触发器会严重减慢数据操作,特别是在数据频繁修改的数据库中。
3、不记录日志的更新不会引起DML触发器的触发(如WRITETEXT、Trunacte table及批量插入操作。
4、约束通常比触发器运行更快。
5、处理某些逻辑时,存储过程通常比触发器要更易维护和管理。
6、不允许在触发器中使用Select返回结果集。
示例:
USE tempdb
GO
--创建两个测试表
IF NOT Object_id('DepartDemo')ISNULL
DROPTABLE[DepartDemo]
GO
IF NOT Object_id('DepartChangeLogs')ISNULL
DROPTABLE[DepartChangeLogs]
GO
--测试表
CREATETABLE[dbo].[DepartDemo]
(
[DID] [INT]NOTNULL,
[DName][NVARCHAR](200)NULL,
)
GO
--记录日志表
CREATETABLE[DepartChangeLogs]
(
[DID] [INT]NOTNULL,
[DName] [NVARCHAR](200)NULL,
[LogTime] DATETIMEDEFAULT(Getdate())NOTNULL,
[InsOrUpd]CHARNOTNULL
)
GO
/******* 创建一个After DML触发器 ******/
CREATETRIGGERdbo.tri_LogDepartDemo
ON [dbo].[DepartDemo]
AFTERINSERT,DELETE/************此处使用update与“Insert,Delete”效果是一样的 **********/
AS
SETNOCOUNTON--屏蔽触发器发送“受影响的行数”给应用程序
-- Insertedrows
INSERT[DepartChangeLogs]
SELECT*, Getdate(), 'I' FROM insertedi
-- Deletedrows
INSERT[DepartChangeLogs]
SELECTDISTINCT*, Getdate(), 'D' FROM deletedd
--①INSERT
INSERT[dbo].[DepartDemo] VALUES('1', 'wangshuting')
--②UPDATE★该Update不会被触发器记录,但Update会生效★--
UPDATE departDemo SET [DName]='任我行' WHERE DID= 1
--③DELETE
DELETEFROM departDemo WHERE DID= 1
SELECT * FROM [DepartDemo]
SELECT * FROM [DepartChangeLogs]
--禁止操作的触发器
CREATETRIGGERdbo.[tri_LogDepartDemo2]
ON [dbo].[DepartDemo]
AFTERUPDATE
AS
IF ( Update([DName])
ORUpdate([DID]))
BEGIN
PRINT'该人员不得中途更改!'
ROLLBACK----回滚Update操作
END
GO
UPDATE departDemo SET [DName]='任我行' WHERE DID= 1
DELETEFROM departDemo WHERE DID= 1
GO
返回受INSERT、UPDATE、DELETE 或 MERGE 语句影响的各行中的信息,或返回基于受这些语句影响的各行的表达式。
注意点:
1、从OUTPUT 中返回的列反映 INSERT、UPDATE 或 DELETE 语句完成之后但在触发器执行之前的数据。
2、SQL Server 并不保证由使用 OUTPUT 子句的 DML 语句处理和返回行的顺序。
3、与触发器相比,OutPut子句可以直接处理Merge语句。
示例:
DROPTABLEdbo.table1,dbo.table1Logs,dbo.table2
CREATETABLEdbo.table1
(
id INT,
employeeVARCHAR(32)
)
CREATETABLEdbo.table1Logs
(
id INT,
employeeVARCHAR(32),
Curtime DATETIME,
Remark VARCHAR(32)
)
INSERTINTOdbo.table1
VALUES(1,'Fred'), (2,'Tom'), (3,'Sally'), (4,'Alice');
--①delete
DELETE FROM dbo.table1
OUTPUT DELETED.*, Getdate(), 'D' INTO table1Logs WHERE id= 4 OR id= 2;
SELECT * FROM dbo.table1;
SELECT * FROM table1Logs;
--②insert
INSERT INTO dbo.table1
OUTPUT INSERTED.*, Getdate(), 'I' INTOtable1Logs VALUES('5', 'Wendy')
SELECT * FROM dbo.table1;
SELECT * FROM table1Logs;
--③update
UPDATE dbo.table1 SET employee='wangshuting'
OUTPUT DELETED.*, Getdate(), 'U' INTO table1Logs--可用INSERTED
WHERE id = 5
SELECT * FROM dbo.table1;
SELECT * FROM table1Logs;
--④merge
CREATETABLEdbo.table2
(
id INT,
employeeVARCHAR(32)
)
INSERT INTO dbo.table2 VALUES ('1', 'Fred-change'), ('9', 'xiena');
MERGE INTO table1 a USING dbo.table2 b
ON a.id =b.id
WHEN MATCHED THEN UPDATE SET a.employee=b.employee--可用INSERTED
WHEN NOT MATCHED THEN INSERT VALUES(b.id, b.employee)--不可用INSERTED
OUTPUTINSERTED.*, Getdate(), 'M' INTOtable1Logs;
SELECT * FROM dbo.table1;
SELECT *FROM table1Logs;
实现异步跟踪用户表的数据修改,而且这一功能拥有最小的性能开销。
下图说明了变更数据捕获的主体数据流
变更数据捕获的更改数据源为 SQLServer 事务日志。(因此需要SQL Agent服务的支持)
在将插入、更新和删除应用于跟踪的源表时,将会在日志中添加说明这些更改的项。日志用作变更数据捕获进程的输入来源。它会读取日志,并在跟踪的表的关联更改表中添加有关更改的信息。将提供一些函数,以枚举在更改表中指定范围内发生的更改,并以筛选的结果集的形式返回该值。通常,应用程序进程使用筛选的结果集在某种外部环境中更新源表示形式。
变更数据捕获的条件:
①SQL Agent服务需要打开。
②仅在SQLServer2008(含)以后的企业版、开发版和评估版中可用。
③执行者需要用sysadmin角色权限
_CT更改表 :每个捕获的实例对应一张名为cdc.
示例:
CREATEDATABASEtest1
USE test1
CREATETABLE[dbo].[WSTtestTBL]
(
[id] [INT]IDENTITY(1, 1)NOTNULL,
[name][NVARCHAR](20)NULL
)
ON [PRIMARY]
sp_cdc_enable_db--对当前数据库启用变更数据捕获
SELECTis_cdc_enabled
FROM sys.databases
WHERE name='test1'--对数据库启用变更数据捕获成功
sp_cdc_enable_table@source_schema='dbo',@source_name='WSTtestTBL',@role_name='cdc_role'--源表标识为跟踪的表(条件:启动SQLServerAgent服务)
--EXECUTEsys.sp_cdc_help_change_data_capture --指定表的变更数据捕获配置信息
-- @source_schema = N'dbo',
-- @source_name = N'WSTtestTBL';
--GO
INSERT INTO WSTtestTBL VALUES('jiayiw')
DELETE FROM WSTtestTBL WHERE name='jiayiw'
INSERT INTO WSTtestTBLVALUES('wangshuting')
UPDATE WSTtestTBL SET name='zhangjie'
WHERE NAME='wangshuting'
--SELECT *FROM WSTtestTBL
SELECT * FROM cdc.dbo_WSTtestTBL_CT
--__$operation=2的情况,表示新增
--__$operation=3或者4,表示更新,3表示旧值,4表示新值
--__$operation=1的情况,表示删除
对表开启以后,可以在下图中看到多了很多cdc架构开头的表:
启动之后,可以看到SQLServer代理里面的作业,也出现了这两个作业:
下面列出相关的存储过程:
函数:
变更数据捕获为有效地执行从源表到数据市场和数据仓库的增量加载提供了一种颇有成效的解决方案。
下面的关系图显示的步骤用于创建一个从单表执行增量加载的包:
①变量名 DataReady,其初始值为 0。
数据类型为 integer,以保存执行 SQL 任务返回的状态值。
②变量名 DelaySeconds,其初始值为 10。
以保存数据未准备就绪时的延迟时间。
如果您计划使用脚本任务来实现延迟,该变量的数据类型应为 integer。
如果您计划使用含有 WAITFOR 语句的执行 SQL 任务,则应为 string。
③变量名 TimeoutCount,其初始值为 0。
数据类型为 integer 的变量,以保存循环的当前迭代。
④变量名 TimeoutCeiling,其初始值为 20。
数据类型为 integer 的变量,以指定循环在报告超时情况之前应对数据执行的测试次数。
⑤(可选)变量名 IntervalID,并且仅检查 0 值以指示首次加载。
数据类型为 integer 的变量以指示变更数据的首次加载。
1、变更捕获表中必须存在主键,或者唯一标示的字段(自增列)。如WSTtestTBL自增列id
2、IntervalID=1,非首次加载。对表进行数据捕获后,对目标表执行一次存量后,
再执行增量加载包。
返回值 |
含义 |
响应 |
0 |
指示变更数据未准备就绪。在所选间隔的结束点之后没有变更数据捕获记录。 |
执行过程通过实现延迟的组件继续执行。然后该控件返回 For循环容器,只要返回值为 0,就会继续检查执行 SQL任务。 |
1 |
可能指示没有捕获到整个间隔的变更数据,或者变更数据已删除。这被视为错误情况。在所选间隔的起始点之前没有变更数据捕获记录。 |
执行过程通过记录错误的可选组件继续执行。 |
2 |
指示数据已准备就绪。在所选间隔的起始点之前和结束点之后都存在变更数据捕获记录。 |
执行将跳出 For循环容器并且增量加载开始进行。 |
3 |
指示所有可用的变更数据的首次加载。条件逻辑从仅用于此目的特殊包变量中获取此值。 |
执行将跳出 For循环容器并且增量加载开始进行。 |
5 |
指示已达到 TimeoutCeiling。循环已对数据执行了指定次数的测试,数据仍不可用。如果没有此测试或类似的测试,该包可能会无限期地运行。 |
执行过程通过记录超时的可选组件继续执行 |
此包的变更间隔使用固定间隔,并假定无例外的情况下增量加载包每天运行。即今天对目标表执行昨日的源表数据捕获变更。改善:用日志表记录包上次执行的endtime作为此次执行的startime,以适应非固定间隔。
SQL Server 2008中新增的“更改跟踪”却是一个同步进程,是DML操作本身(I/D/U)事务的一部分,它的最大优势是以最小的磁盘开销来侦测净行变更,
它允许修改的数据以事务一致的形式表现,并提供了检测数据冲突的能力。它甚至可以根据外部传入的应用程序上下文,来完成更细颗粒度的更改处理。
功能 |
更改跟踪 |
更改数据捕获 |
同步 |
是 |
否 |
需要 SQL代理 |
否 |
是 |
强制完整记录一些大型操作 |
否 |
是 |
防止日志截断 |
否 |
是,必须等到日志记录都搜集完成 |
需要快照隔离 |
建议 |
否 |
需要不同的表来存储跟踪数据 |
是 |
是 |
需要主键 |
是 |
并非默认 |
允许确定跟踪表的位置 |
否 |
是 |
可能出现空间消耗问题 |
有些 |
很多 |
自动清除过程 |
是 |
是 |
对 DDL有限制 |
是 |
否 |
启用所需的权限 |
系统管理员 |
数据库所有 |
1、不建议前两个。
2、CDC用以实现异步跟踪用户表的数据修改,而且这一功能拥有最小的性能开销,可以用于其他数据源的持续更新,
例如将OLTP数据库中的数据变更迁移到数据仓库数据库。
3、“更改跟踪”的最大优势是以最小的磁盘开销来侦测净行变更,它允许修改的数据以事务一致的形式表现,并提供了检测数据冲突的能力。
http://msdn.microsoft.com/zh-cn/library/ms189799.aspx
http://technet.microsoft.com/zh-cn/library/ms177564.aspx
http://msdn.microsoft.com/zh-cn/library/bb895315(v=sql.100).aspx