SQL点滴24 监测表的变化

有时候,我们在某一重要的时间段需要监控某张表的变化情况,包含插入、更新、删除。举例来说,当我们把数据导出到外部的系统时,我们希望导出的是全部的数据,而且最好是导出上次导出之后变动的数据。
作为DBA,我们可采传统的触发器操作,来构建一个元数据表或一个时间戳列来监控数据的变化。
代码如下:Code Listing 1
该代码在 SQL 2005(SP3), SQL 2008 R2 (RTM with cu5)测试通过


代码如下:

-------------------
--Method 1: TRIGGER
-------------------
--Base Table Definition
IF OBJECT_ID('CheckSumTest', 'U') IS NOT NULL DROP TABLE CheckSumTest
GO
CREATE TABLE CheckSumTest
(
id int IDENTITY(1,1) NOT NULL PRIMARY KEY,
vc1 varchar(1) NOT NULL,
vc2 varchar(1) NOT NULL
)
GO
INSERT dbo.CheckSumTest (vc1, vc2) SELECT 'a', 'b'
INSERT dbo.CheckSumTest (vc1, vc2) SELECT 'b', 'a'
GO
--Create Audit Summary Table to hold Meta-Data
IF OBJECT_ID('dbo.TableAuditSummary', 'U') IS NOT NULL DROP TABLE dbo.TableAuditSummary
CREATE TABLE dbo.TableAuditSummary
( id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
TableName sysname NOT NULL,
LastUpdate DATETIME NOT NULL,
LastExport DATETIME NOT NULL
)
GO
INSERT dbo.TableAuditSummary (TableName, LastUpdate, LastExport) VALUES ('dbo.CheckSumTest', GETDATE(), GETDATE())
GO
--Tables that need exporting
SELECT * FROM dbo.TableAuditSummary WHERE LastUpdate>LastExport
--Create Trigger on all Base Tables
--This fires on any insert/update/delete and writes new LastUpdate column for the table set to Current Date and Time
IF OBJECT_ID('dbo.trg_CheckSumTest_MaintainAuditSummary', 'TR') IS NOT NULL DROP TRIGGER dbo.trg_CheckSumTest_MaintainAuditSummary
GO
CREATE TRIGGER dbo.trg_CheckSumTest_MaintainAuditSummary
ON dbo.CheckSumTest
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
IF (object_id('dbo.CheckSumTest') IS NOT NULL)
UPDATE dbo.TableAuditSummary SET LastUpdate=GETDATE() WHERE TableName='dbo.CheckSumTest'
END
GO
--Make an Update
UPDATE dbo.CheckSumTest SET vc1='b', vc2='a' WHERE id=1
UPDATE dbo.CheckSumTest SET vc1='a', vc2='b' WHERE id=2
--Check Meta-Data
SELECT * FROM dbo.TableAuditSummary WHERE LastUpdate>LastExport
--When we have Exported the data, we run the following to reset MetaData
UPDATE dbo.TableAuditSummary SET LastExport=GETDATE() WHERE LastUpdate>LastExport

最近我正在读关天SQLSERVER在线帮助(BOL)相关的知识, 我接触到了 SQL Server CHECKSUM(), BINARY_CHECKSUM(), and CHECKSUM_AGG() 这几个函数, 由此突然想到这些函数是不是也可以监控表的数据变化,而事实证明CHECKSUM_AGG() 函数尽管被描述为检测表的变化,但这里不适用.
使用 CheckSum() and CheckSum_Agg() 函数
CHECKSUM_AGG() 函数, 在Books OnLine 和许多相关的站点上是这样描述的, 通常用于检测一个表的数据是否更改. 这是一个代替触发器的更好的方法,只是该操作会引起表扫描的操作。于是我这次我仍然使用元数据来跟踪数据的变化,只是新建了列LastChkSum代替了LastUpdate,该列用于保存CHECKSUM_AGG(BINARY_CHECKSUM(*)),它将会在全表中产生一个唯一值,以区别数据的变化情况。
代码如下: Listing 2.


代码如下:

---------------------------------------------
--Method 2 : using CheckSum (not reliable)
---------------------------------------------
--Base Table Definition
IF OBJECT_ID('CheckSumTest', 'U') IS NOT NULL DROP TABLE CheckSumTest
GO
CREATE TABLE CheckSumTest
(
id int IDENTITY(1,1) NOT NULL PRIMARY KEY,
vc1 varchar(1) NOT NULL,
vc2 varchar(1) NOT NULL
)
GO
INSERT dbo.CheckSumTest (vc1, vc2) SELECT 'a', 'b'
INSERT dbo.CheckSumTest (vc1, vc2) SELECT 'b', 'a'
GO
--Create Audit Summary Table to hold Meta-Data
IF OBJECT_ID('dbo.TableAuditSummary', 'U') IS NOT NULL DROP TABLE dbo.TableAuditSummary
CREATE TABLE dbo.TableAuditSummary
( id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
TableName sysname NOT NULL,
LastChkSum INT NOT NULL
)
GO
INSERT dbo.TableAuditSummary (TableName, LastChkSum)
SELECT 'dbo.CheckSumTest', CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest
GO
--Tables that need exporting
SELECT * FROM dbo.TableAuditSummary WHERE TableName='dbo.CheckSumTest'
AND LastChkSum<>(SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest)
UNION ALL
...
--Make a Simple (Single row) Update
UPDATE dbo.CheckSumTest SET vc1='c', vc2='a' WHERE id=1
--Tables that need exporting
SELECT * FROM dbo.TableAuditSummary WHERE TableName='dbo.CheckSumTest'
AND LastChkSum<>(SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest)
UNION ALL
...
--Reset MetaData
UPDATE dbo.TableAuditSummary SET LastChkSum=(SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest)
WHERE TableName='dbo.CheckSumTest'
--Make a Symmetric change
UPDATE dbo.CheckSumTest SET vc1='b', vc2='a' WHERE id=1
UPDATE dbo.CheckSumTest SET vc1='c', vc2='a' WHERE id=2
--Tables that need exporting (no rows returned as CHECKSUM_AGG() has not changed!!)
SELECT * FROM dbo.TableAuditSummary WHERE TableName='dbo.CheckSumTest'
AND LastChkSum<>(SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest)
UNION ALLCode Listing 2

正如你所看到的那样,对于单个的变化的情况,CHECKSUM是使用比较好的,但是CHECKSUM_AGG()却不能反应数据的变化
代码如下:Code Listing 3


代码如下:

--Base Table Definition
IF OBJECT_ID('CheckSumTest', 'U') IS NOT NULL DROP TABLE CheckSumTest
GO
CREATE TABLE CheckSumTest
(
id int IDENTITY(1,1) NOT NULL PRIMARY KEY,
vc1 varchar(1) NOT NULL,
vc2 varchar(1) NOT NULL,
chksum1 AS (CHECKSUM(id, vc1, vc2)),
chksum2 AS (BINARY_CHECKSUM(id, vc1, vc2))
)
GO
INSERT dbo.CheckSumTest (vc1, vc2) SELECT 'a', 'b'
INSERT dbo.CheckSumTest (vc1, vc2) SELECT 'b', 'a'
GO
--Show Computed Columns and CheckSum_Agg() value = 199555
SELECT * FROM CheckSumTest
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM CheckSumTest
--Make a Simple (Single row) Update
UPDATE dbo.CheckSumTest SET vc1='c', vc2='a' WHERE id=1
--Show Computed Columns and CheckSum_Agg() value = 204816 (Ok)
SELECT * FROM CheckSumTest
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM CheckSumTest
--Make a Symmetric change
UPDATE dbo.CheckSumTest SET vc1='b', vc2='a' WHERE id=1
UPDATE dbo.CheckSumTest SET vc1='c', vc2='a' WHERE id=2
--Show Computed Columns and CheckSum_Agg() value = 204816 (Not Ok!)
SELECT * FROM CheckSumTest
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM CheckSumTest

我们会发现调整前后 CHECKSUM_AGG(BINARY_CHECKSUM(*)) 的值是一样的,不能区分
结论:
CHECKSUM_AGG() 函数尽管被描述为能监测表数据的变化,在实际测试中是不行的。尤其是对表进行对称数据修改时,无法监测
作者:Tyler Ning

(0)

相关推荐

  • SQL点滴24 监测表的变化

    有时候,我们在某一重要的时间段需要监控某张表的变化情况,包含插入.更新.删除.举例来说,当我们把数据导出到外部的系统时,我们希望导出的是全部的数据,而且最好是导出上次导出之后变动的数据. 作为DBA,我们可采传统的触发器操作,来构建一个元数据表或一个时间戳列来监控数据的变化. 代码如下:Code Listing 1 该代码在 SQL 2005(SP3), SQL 2008 R2 (RTM with cu5)测试通过 复制代码 代码如下: ------------------- --Method

  • 监听mysql表内容变化 mysql开启binlog

    前言 binlog 就是binary log,二进制日志文件,这个文件记录了mysql所有的增.删.改语句.通过binlog日志我们可以做数据恢复,做主从复制等等.可以看到,只要有了这个binlog,我们就拥有了mysql的完整备份了. 我们时常会碰到这样的需求,就是要监听某个表的变化,然后来做一些操作. 如果该表数据只增加.不删除修改的话,要监听比较简单,可以定时去查询最新的id即可.但要有删除.修改操作的话,免不了就得全表扫描,效率极低.倘若该表发生变化时,能触发个事件之类的可供监听,那最好

  • 利用SQL Server触发器实现表的历史修改痕迹记录

    在很多应用程序开发中,需要记录某些数据表的历史记录或修改痕迹,以便日后出现数据错误时进行数据排查.这种业务需求,我们可以通过数据库的触发器来轻松实现历史记录功能. 本文以SQL Server 2005数据库中的触发器为例(因为手中的项目用的就是这个数据库) 先简单描述一下SQL Server触发器. SQL Server触发器的inserted和deleted SQL Server为每个触发器都创建了两个专用虚拟表:inserted表和deleted表.这两个表由系统来维护,他们存在于内存中,而

  • 仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案

    问题场景 各大平台店铺的三项评分(物流.服务.商品)变化情况: 商品每日价格的变化记录: 股票的实时涨跌浮: 复现场景 表:主键ID,商品编号,记录时的时间,记录时的价格,创建时间. 问题:获取每个商品每次的变化情况(涨跌幅.涨跌率). 解决思路 1.要想高效率的更新涨跌,就肯定不能是逐条数据更新,要通过自连表建立起对应关系,将每一条数据关联到上一次的价格数据. 2.由于数据库非常庞大,所以可能存在很多垃圾数据,就比如说相关的字段值为NULL或者非有效值的,这些数据要先排除掉. SELECT i

  • SQL server 2005的表分区

    下面来说下,在SQL SERVER 2005的表分区里,如何对已经存在的有数据的表进行分区,其实道理和之前在http://www.cnblogs.com/jackyrong/archive/2006/11/13/559354.html说到一样,只不过交换下顺序而已,下面依然用例子说明:   依然在c盘的data2目录下建立4个文件夹,用来做4个文件组,然后建立数据库 use masterIF  EXISTS (SELECT name FROM sys.databases WHERE name =

  • SQL Server 2012 多表连接查询功能实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: -- 交叉连接产生笛卡尔值 (X*Y) SELECT * FROM Student cross Join dbo.ClassInfo --另外一种写法 SELECT * FROM Student , ClassInfo -- 内连接 (Inner 可以省略) SELECT * FROM Student JOIN dbo.ClassInfo ON dbo.Student.Class = dbo.ClassInfo.ID; -- Inner Jo

  • Sql Server中判断表、列不存在则创建的方法

    一.Sql Server中如何判断表中某列是否存在 首先跟大家分享Sql Server中判断表中某列是否存在的两个方法,方法示例如下: 比如说要判断表A中的字段C是否存在两个方法: 第一种方法  IF EXISTS ( SELECT 1 FROM SYSOBJECTS T1 INNER JOIN SYSCOLUMNS T2 ON T1.ID=T2.ID WHERE T1.NAME='A' AND T2.NAME='C' ) PRINT '存在' ELSE PRINT '不存在' 第二种方法,短小

  • SQL Server 存储过程遇到“表 ''#TT'' 没有标识属性无法执行 SET 操作”错误

    创建临时表,往临时表插入数据的时候报的错误. 一开始提示没有打开主键,后来打开主键就提示上述错误异常. 从网上查找资料没有找到,然后又到群里问各位大牛,一位大牛告诉我是没有设置主键. 我又仔细看看提示,恍然大悟,我就给临时设置了主键. 没有主键之前的代码: CREATE TABLE #TT( CourseId INT , UserId INT, ClassId INT ) INSERT INTO #TT ( CourseId, UserId, ClassId ) SELECT CourseId,

  • MySQL中使用SQL语句查看某个表的编码方法

    MySQL中,如何使用SQL语句来查看某个表的编码呢?我们使用show create table 这一SQL语句来解决这个问题. show create table可以查看创建这个表的SQL语句脚本,它的基本语法是: show create table <表名>; 我们用它看看test表的create脚本: mysql> show create table test; +-------+--------------------------------------------- -----

  • Orancle的SQL语句之多表查询和组函数

    一.SQL的多表查询: 1.左连接和右连接(不重要一方加(+)) SELECT e.empno,e.ename,d.deptno,d.dname,d.loc FROM emp e,dept d WHERE e.deptno(+)=d.deptno ; (+)在等号左边是右连接,反之左连接. 2.交叉连接 (CROSS JOIN产生笛卡尔积) SELECT * FROM emp CROSS JOIN dept ; 3.自然连接 (NATURAL JOIN)自动关联字段匹配 SELECT * FRO

随机推荐