检查对SQL Server表的更改吗?
如何监视SQL Server数据库对表的更改而不使用触发器或以任何方式修改数据库的结构? 我的首选编程环境是.NET和C#。
我希望能够支持任何SQL Server 2000 SP4或更新版本。 我的应用程序是另一家公司产品的螺栓式数据可视化。 我们的客户群是数千人,所以我不希望在每次安装时都要求我们修改第三方供应商的表格。
通过“更改到表”我的意思是更改表数据,而不是更改表结构。
最终,我希望更改在我的应用程序中触发事件,而不必每隔一段时间检查一次更改。
根据我的要求(无触发器或架构修改,SQL Server 2000和2005),最好的方法似乎是在T-SQL中使用BINARY_CHECKSUM
函数。 我打算实施的方式是这样的:
每X秒运行以下查询:
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);
并将其与储值进行比较。 如果值已更改,请使用查询逐行浏览表:
SELECT row_id, BINARY_CHECKSUM(*) FROM sample_table WITH (NOLOCK);
并比较返回的校验和与存储的值。
看看CHECKSUM命令:
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);
只要表内容没有改变,每次运行时都会返回相同的数字。 请参阅我的文章了解更多信息:
校验
在更改表格时,我使用它来重buildcaching依赖关系:
ASP.NET 1.1数据库caching依赖(不带触发器)
不幸的是,CHECKSUM不能正常工作来检测变化 。 这只是一个原始校验和,没有CRC计算。 因此,您不能使用它来检测所有更改,例如对称更改导致同一个CHECKSUM!
例如, 带有CHECKSUM_AGG(BINARY_CHECKSUM(*))
的解决scheme为所有3个不同内容的表提供始终为0的解决scheme!
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 1 as numA, 1 as numB UNION ALL SELECT 1 as numA, 1 as numB ) q -- delivers 0!
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 1 as numA, 1 as numB UNION ALL SELECT 1 as numA, 1 as numB ) q -- delivers 0!
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))FROM
(
SELECT 1作为numA,2作为numB
联盟所有
SELECT 1作为numA,2作为numB
)q
– 交付0!
SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))FROM
(
SELECT 0作为numA,0作为numB
联盟所有
SELECT 0作为numA,0作为numB
)q
– 交付0!
你为什么不想使用触发器? 如果你正确使用它们,这是一件好事。 如果你用它们来强化参照完整性,那就是当它们从好到坏。 但是,如果你使用它们进行监控,那么它们并不被认为是禁忌。
您需要多长时间检查一次数据库中的更改,以及数据库中的表的大小(行大小)? 如果使用Johnbuild议的CHECKSUM_AGG(BINARY_CHECKSUM(*))
方法,它将扫描指定表的每一行。 NOLOCK
提示有帮助,但是在大型数据库上,您仍然每行都有。 您还需要存储每行的校验和,以便您可以告诉您已经更改。
你有没有考虑过从另一个angular度来看这个呢? 如果你不想修改模式来添加触发器(这是有道理的,这不是你的数据库),你有没有考虑与使数据库的应用程序供应商合作?
他们可以实现一个API,提供一种通知配件应用程序数据已经改变的机制。 这可以像写入通知表一样简单,该通知表列出哪些表和哪一行被修改。 这可以通过触发器或应用程序代码来实现。 从你身边,ti无所谓,唯一的担心就是定期扫描通知表。 数据库的性能将远远低于扫描每一行的变化。
最困难的部分将是说服应用程序供应商实现此function。 由于这可以通过触发器完全通过SQL进行处理,因此可以通过编写和testing触发器然后将代码带到应用程序供应商来完成大部分工作。 通过让供应商支持触发器,它可以防止添加触发器无意中replace供应商提供的触发器的情况。
有一个以给定间隔运行的DTS作业(或由Windows服务启动的作业)。 每次运行时,都会使用系统INFORMATION_SCHEMA表获取有关给定表的信息 ,并将这些数据logging在数据存储库中。 将返回的关于表格结构的数据与前一次返回的数据进行比较。 如果不一样,那么你知道结构已经改变了。
示例查询返回有关表ABC中所有列的信息(理想情况下,仅列出您想要的INFORMATION_SCHEMA表中的列,而不是像我这样使用* select **):
select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'
您可以监视不同的列和INFORMATION_SCHEMA视图,具体取决于您如何定义“对表的更改”。
不幸的是,我不认为在SQL2000中有一个干净的方法来做到这一点。 如果您将需求缩小到SQL Server 2005(及更高版本),那么您已经开始工作。 您可以在System.Data.SqlClient
使用SQLDependency
类。 请参阅SQL Server中的查询通知(ADO.NET) 。
疯狂的猜测在这里:如果你不想修改第三方的表,你可以创build一个视图,然后在该视图上放置一个触发器?
检查最后的提交date。 每个数据库都有每次提交的历史logging。 我相信它是符合ACID标准的。