SQL点滴24—监测表的变化

原文:SQL点滴24—监测表的变化(转载)

在网上看到一篇关于监测表中的插入,更新,删除的方法,使用触发器实现的,很有价值。

地址:http://www.dbaunion.com/u/livecoach/Blog.aspx/t-19

有时候,我们在某一重要的时间段需要监控某张表的变化情况,包含插入、更新、删除。举例来说,当我们把数据导出到外部的系统时,我们希望导出的是全部的数据,而且最好是导出上次导出之后变动的数据。

作为DBA,我们可采传统的触发器操作,来构建一个元数据表或一个时间戳列来监控数据的变化。

代码如下:Code Listing 1

该代码在 SQL 2005(SP3), SQL 2008 R2 (RTM with cu5)测试通过

---------------------Method 1: TRIGGER---------------------Base Table DefinitionIF OBJECT_ID(‘CheckSumTest‘, ‘U‘) IS NOT NULL DROP TABLE CheckSumTestGOCREATE TABLE CheckSumTest(        id                      int                     IDENTITY(1,1) NOT NULL PRIMARY KEY,        vc1                     varchar(1)      NOT NULL,        vc2                     varchar(1)      NOT NULL)GOINSERT dbo.CheckSumTest (vc1, vc2) SELECT ‘a‘, ‘b‘INSERT dbo.CheckSumTest (vc1, vc2) SELECT ‘b‘, ‘a‘GO--Create Audit Summary Table to hold Meta-DataIF OBJECT_ID(‘dbo.TableAuditSummary‘, ‘U‘) IS NOT NULL DROP TABLE dbo.TableAuditSummaryCREATE TABLE dbo.TableAuditSummary(       id                      INT                     IDENTITY(1,1)   NOT NULL PRIMARY KEY,        TableName       sysname         NOT NULL,        LastUpdate      DATETIME        NOT NULL,        LastExport      DATETIME        NOT NULL)GOINSERT dbo.TableAuditSummary (TableName, LastUpdate, LastExport) VALUES (‘dbo.CheckSumTest‘, GETDATE(), GETDATE())GO--Tables that need exportingSELECT * 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 TimeIF OBJECT_ID(‘dbo.trg_CheckSumTest_MaintainAuditSummary‘, ‘TR‘) IS NOT NULL DROP TRIGGER dbo.trg_CheckSumTest_MaintainAuditSummaryGOCREATE TRIGGER dbo.trg_CheckSumTest_MaintainAuditSummaryON dbo.CheckSumTestAFTER INSERT, UPDATE, DELETEASBEGIN        IF (object_id(‘dbo.CheckSumTest‘) IS NOT NULL)                UPDATE dbo.TableAuditSummary SET LastUpdate=GETDATE() WHERE TableName=‘dbo.CheckSumTest‘ENDGO--Make an UpdateUPDATE dbo.CheckSumTest SET vc1=‘b‘, vc2=‘a‘ WHERE id=1UPDATE dbo.CheckSumTest SET vc1=‘a‘, vc2=‘b‘ WHERE id=2--Check Meta-DataSELECT * FROM dbo.TableAuditSummary WHERE LastUpdate>LastExport--When we have Exported the data, we run the following to reset MetaDataUPDATE 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 DefinitionIF OBJECT_ID(‘CheckSumTest‘, ‘U‘) IS NOT NULL DROP TABLE CheckSumTestGOCREATE TABLE CheckSumTest( id int IDENTITY(1,1) NOT NULL PRIMARY KEY, vc1 varchar(1) NOT NULL, vc2 varchar(1) NOT NULL)GOINSERT dbo.CheckSumTest (vc1, vc2) SELECT ‘a‘, ‘b‘INSERT dbo.CheckSumTest (vc1, vc2) SELECT ‘b‘, ‘a‘GO--Create Audit Summary Table to hold Meta-DataIF OBJECT_ID(‘dbo.TableAuditSummary‘, ‘U‘) IS NOT NULL DROP TABLE dbo.TableAuditSummaryCREATE TABLE dbo.TableAuditSummary( id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, TableName sysname NOT NULL, LastChkSum INT NOT NULL)GOINSERT dbo.TableAuditSummary (TableName, LastChkSum) SELECT ‘dbo.CheckSumTest‘, CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTestGO--Tables that need exportingSELECT * FROM dbo.TableAuditSummary WHERE TableName=‘dbo.CheckSumTest‘ AND LastChkSum<>(SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest)UNION ALL...--Make a Simple (Single row) UpdateUPDATE dbo.CheckSumTest SET vc1=‘c‘, vc2=‘a‘ WHERE id=1--Tables that need exportingSELECT * FROM dbo.TableAuditSummary WHERE TableName=‘dbo.CheckSumTest‘ AND LastChkSum<>(SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest)UNION ALL...--Reset MetaDataUPDATE dbo.TableAuditSummary SET LastChkSum=(SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM dbo.CheckSumTest) WHERE TableName=‘dbo.CheckSumTest‘--Make a Symmetric changeUPDATE dbo.CheckSumTest SET vc1=‘b‘, vc2=‘a‘ WHERE id=1UPDATE 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 DefinitionIF OBJECT_ID(‘CheckSumTest‘, ‘U‘) IS NOT NULL DROP TABLE CheckSumTestGOCREATE 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)))GOINSERT dbo.CheckSumTest (vc1, vc2) SELECT ‘a‘, ‘b‘INSERT dbo.CheckSumTest (vc1, vc2) SELECT ‘b‘, ‘a‘GO--Show Computed Columns and CheckSum_Agg() value = 199555SELECT * FROM CheckSumTest SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM CheckSumTest--Make a Simple (Single row) UpdateUPDATE 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 changeUPDATE dbo.CheckSumTest SET vc1=‘b‘, vc2=‘a‘ WHERE id=1UPDATE 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() 函数尽管被描述为能监测表数据的变化,在实际测试中是不行的。尤其是对表进行对称数据修改时,无法监测

时间: 2024-07-31 05:37:46

SQL点滴24—监测表的变化的相关文章

sql点滴40—mysql乱码问题总结

原文:sql点滴40-mysql乱码问题总结 本文将为大家讲解如何处理Java连接过程中的MySQL中文乱码问题.一般MySQL中文乱码问题都是与字符集有关,这里作者的经历也大致差不多. MySQL默认编码是latin1 1. mysql> show variables like 'character%'; 2. +--------------------------+--------------------------+ 3. | Variable_name | Value | 4. +---

SQL点滴18—SqlServer中的merge操作,相当地风骚

原文:SQL点滴18-SqlServer中的merge操作,相当地风骚 今天在一个存储过程中看见了merge这个关键字,第一个想法是,这个是配置管理中的概念吗,把相邻两次的更改合并到一起.后来在technet上搜索发现别有洞天,原来是另外一个sql关键字,t-sql的语法还是相当地丰富的.本篇是一篇学习笔记,没有什么新意,这里给出technet上的地址连接供大家参考权威:http://technet.microsoft.com/zh-cn/library/bb510625.aspx,这里具体的语

SQL点滴10—使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比

原文:SQL点滴10-使用with语句来写一个稍微复杂sql语句,附加和子查询的性能对比 今天偶尔看到sql中也有with关键字,好歹也写了几年的sql语句,居然第一次接触,无知啊.看了一位博主的文章,自己添加了一些内容,做了简单的总结,这个语句还是第一次见到,学习了.我从简单到复杂地写,希望高手们不要见笑.下面的sql语句设计到三个表,表的内容我用txt文件复制进去,这里不妨使用上一个随笔介绍的建立端到端的package的方法将这些表导入到数据库中,具体的就不说了. 从这里下载文件employ

SQL点滴13—收集SQLServer线程等待信息

原文:SQL点滴13-收集SQLServer线程等待信息 要知道线程等待时间是制约SQL Server效率的重要原因,这一个随笔中将学习怎样收集SQL Server中的线程等待时间,类型等信息,这些信息是进行数据库优化的依据. sys.dm_os_wait_stats 这是一个系统视图,里面存储线程所遇到的所有的等待信息,具体的列如下表 列名 数据类型 说明 Wait_type Nvarchar(60) 等待类型名称 waiting_tasks_count Bigint 等待类型的等待数.该计数

SQL点滴22—性能优化没有那么神秘

原文:SQL点滴22-性能优化没有那么神秘 经常听说SQL Server最难的部分是性能优化,不禁让人感到优化这个工作很神秘,这种事情只有高手才能做.很早的时候我在网上看到一位高手写的博客,介绍了SQL优化的问题,从这些内容来看,优化并不都是一些很复杂的问题,掌握了基本的知识之后也可以尝试优化自己的SQL程序,甚至是其他相关的程序.优化是一些工作积累之后的经验总结和代码意识,只要平时注意积累,你也可以做优化的工作.这一篇随笔是转载,不过我强烈推荐给所有对数据库优化有兴趣的博友,读了这一篇之后下一

SQL点滴19—T-SQL中的透视和逆透视

原文:SQL点滴19-T-SQL中的透视和逆透视 透视 今天抽一点时间来看看透视和逆透视语句,简单的说就是行列转换.假设一个销售表中存放着产品号,产品折扣,产品价格三个列,每一种产品号可能有多种折扣,每一种折扣只对应一个产品价格.下面贴出建表语句和插入数据语句. 1 create table SalesOrderDetail( 2 ProductID int /*unique多谢wuu00的提醒*/, 3 UnitPriceDiscount float, 4 ProductPrice float

sql点滴42—mysql中的数据结构

MySQL 的数值数据类型可以大致划分为两个类别,一个是整数,另一个是浮点数或小数.许多不同的子类型对这些类别中的每一个都是可用的,每个子类型支持不同大小的数据,并且 MySQL 允许我们指定数值字段中的值是否有正负之分或者用零填补. 表列出了各种数值类型以及它们的允许范围和占用的内存空间. 类型 大小 范围(有符号) 范围(无符号) 用途 TINYINT 1 字节 (-128,127) (0,255) 小整数值 SMALLINT 2 字节 (-32 768,32 767) (0,65 535)

sql点滴41—MyISAM 和 InnoDB 讲解

InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能. 以下是一些细节和具体实现的差别: 1.InnoDB不支持FULLTEXT类型的索引. 2.InnoDB 中不保存表的具体行数,也就是说,执行select count(

sql点滴37—mysql中的错误Data too long for column &#39;&#39; at row 1

原文:sql点滴37-mysql中的错误Data too long for column '' at row 1   1.MYSQL服务 我的电脑——(右键)管理——服务与应用程序——服务——MYSQL——开启(停止.重启动) 2.命令行方式 Windows 1.点击“开始”->“运行”(快捷键Win+R). 2.启动:输入 net stop mysql 3.停止:输入 net start mysql 提示* Redhat Linux 也支持service command,启动:# servic