检查对SQL Server表的更改吗?

如何在不使用触发器或以任何方式修改数据库结构的情况下监视SQL Server数据库对表的更改?我喜欢的编程环境是 .NET 和C#。

我希望能够支持任何 SQL Server 2000 SP4或更新的版本。我的应用程序是另一家公司产品的螺栓式数据可视化。我们的客户群有数千人,因此我不希望在每次安装时都要求我们修改第三方供应商的表格。

通过“更改为表”我的意思是对表数据的更改,而不是对表结构的更改。

最终,我希望更改在我的应用程序中触发事件,而不必每隔一段时间检查一次更改。


根据我的要求(没有触发器或架构修改,SQL Server 2000和2005),最好的方法似乎是使用 BINARY_CHECKSUM 函数。 org / wiki / Transact-SQL“rel =”noreferrer“> T-SQL 。我打算实施的方式是这样的:

每X秒运行以下查询:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))
FROM sample_table
WITH (NOLOCK);

并将其与储值进行比较。如果值已更改,请使用查询逐行浏览表:

SELECT row_id, BINARY_CHECKSUM(*)
FROM sample_table
WITH (NOLOCK);

并将返回的校验和与存储的值进行比较。

0
额外 编辑
意见: 14
他们没有碰巧在他们的行上放置最后修改的时间戳,是吗?
额外 作者 zmbq,

8 答案

你为什么不想使用触发器?如果你正确使用它们,它们是一件好事。如果你将它们用作强制参照完整性的一种方式,那就是当它们从好到坏时。但是,如果你使用它们进行监控,那么它们并不被视为禁忌。

0
额外

疯狂的猜测在这里:如果你不想修改第三方的表格,你可以创建一个视图,然后在该视图上放置一个触发器?

0
额外

有一个以给定间隔运行的DTS作业(或由Windows服务启动的作业)。每次运行时,它都会使用系统 INFORMATION_SCHEMA 表,并将这些数据记录在数据存储库中。将有关表格结构的数据与前一次返回的数据进行比较。如果不同,那么你知道结构已经改变。

示例查询返回有关表ABC中所有列的信息(理想情况下,只列出您想要的INFORMATION_SCHEMA表中的列,而不是像以下那样使用* select **):

select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'

根据您如何定义“对表格的更改”,您可以监视不同的列和INFORMATION_SCHEMA视图。

0
额外
问题是关于表数据的变化,而information_schema包含表的模式(列定义)。
额外 作者 too,

您需要多久检查一次更改以及数据库中的表有多大(按行大小而定)?如果您使用John建议的 CHECKSUM_AGG(BINARY_CHECKSUM(*))方法,它将扫描指定表的每一行。 NOLOCK 提示有帮助,但是在大型数据库上,您仍然会碰到每一行。您还需要为每一行存储校验和,以便您告诉一个已更改。

你有没有考虑过从另一个角度来看待这个问题?如果你不想修改模式来添加触发器(这是有道理的,它不是你的数据库),你是否考虑过与创建数据库的应用程序供应商合作?

他们可以实现一个API,该API提供了一种通知配件应用程序数据已更改的机制。它可以像写入通知表一样简单,该通知表列出哪些表和哪一行被修改。这可以通过触发器或应用程序代码来实现。从你身边,ti无所谓,你唯一的担心就是定期扫描通知表。数据库的性能将远远低于扫描每一行的变化。

最困难的部分是让应用程序供应商说服这个功能。由于这可以通过触发器完全通过SQL进行处理,因此您可以通过编写和测试触发器然后将代码提供给应用程序供应商来完成大部分工作。通过让供应商支持触发器,它可以防止添加触发器时无意中替换供应商提供的触发器的情况。

0
额外

看看CHECKSUM命令:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);

只要表格内容没有改变,每次运行它都会返回相同的编号。有关更多信息,请参阅我的文章:

CHECKSUM

Here's how I used it to rebuild cache dependencies when tables changed:
ASP.NET 1.1 database cache dependency (without triggers)

0
额外
校验和可以并最终会失败。如果你的系统接受两组不同的数据会产生相同的校验和,那么你就没有问题。出于这个原因,我不得不摆脱我们大多数系统中的校验和...
额外 作者 LPains,

不幸的是,我不认为在SQL2000中有这样一个干净的方法。如果您将需求缩小到SQL Server 2005(及更高版本),那么您已经开始运营。您可以在 System.Data.SqlClient 中使用 SQLDependency 类。请参阅 SQL Server(ADO.NET)中的查询通知

0
额外

检查最后一次提交日期。每个数据库都有每次提交的历史记录。我相信它是符合ACID标准的。

0
额外

Unfortunately CHECKSUM does not work always properly to detect changes. It is only a primitive checksum and no CRC calculation. Therefore you can't use it to detect all changes, e. g. symmetrical changes result in the same CHECKSUM!

例如,使用 CHECKSUM_AGG(BINARY_CHECKSUM(*))的解决方案为所有3个不同内容的表提供始终为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 as numA, 2 as numB UNION ALL SELECT 1 as numA, 2 as numB ) q -- delivers 0!


SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 0 as numA, 0 as numB UNION ALL SELECT 0 as numA, 0 as numB ) q -- delivers 0!
0
额外
这实际上不是答案,而是“你的建议不起作用”。
额外 作者 kristianp,
通过在BINARY_CHECKSUM之前使用DISINCT关键字,可以修复重复的数据。还有一些其他的陷阱讨论了这里,但不完全常见场景。
额外 作者 pblack,