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

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

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

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


考虑到我的要求(没有触发器或架构修改,SQL Server 2000 和 2005),最好的行动方案似乎是使用 BINARY_CHECKSUM 函数于 T-SQL. 。我计划实施的方式是这样的:

每 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);

只要表内容没有更改,每次运行都会返回相同的数字。有关更多信息,请参阅我的帖子:

校验和

以下是我如何在表更改时使用它来重建缓存依赖项:
ASP.NET 1.1 数据库缓存依赖项(无触发器)

其他提示

不幸的是,CHECKSUM 并不总是能正常工作来检测更改.

它只是一个原始校验和,没有循环冗余校验(CRC)计算。

因此,您不能使用它来检测所有更改,例如。G。对称的变化会产生相同的校验和!

E.G。解决方案与 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!

选择checksum_agg(binary_checksum(*))从(选择1作为numa,2作为numb Union选择1个numa,2作为Numb)q-交付0!

从(从numa中选择0作为numa,numb Union as select 0作为numa,0作为numb)q -select checksum_agg(binary_checksum(*))从(选择0为numa,numb)q-交付0!

为什么不想使用触发器?如果你正确使用它们,它们是一件好事。如果您使用它们作为强制引用完整性的一种方式,那么它们就会从好变坏。但如果你用它们来监控,它们其实并不被认为是禁忌。

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

您是否考虑过从不同的角度来看待这个问题?如果您不想修改架构来添加触发器(这是有道理的,它不是您的数据库),您是否考虑过与制作数据库的应用程序供应商合作?

他们可以实现一个 API,提供一种机制来通知附件应用程序数据已更改。它可以像写入通知表一样简单,其中列出了修改的表和行。这可以通过触发器或应用程序代码来实现。从您这边来看,ti 并不重要,您唯一关心的是定期扫描通知表。对数据库的性能影响远小于扫描每一行以查找更改。

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

不幸的是,我认为在 SQL2000 中没有一种干净的方法可以做到这一点。如果您将需求范围缩小到 SQL Server 2005(及更高版本),那么您就可以开始工作了。您可以使用 SQLDependency 班级在 System.Data.SqlClient. 。看 SQL Server (ADO.NET) 中的查询通知.

拥有按给定时间间隔运行的 DTS 作业(或由 Windows 服务启动的作业)。每次运行时,它都会使用系统获取有关给定表的信息 信息架构 表,并将这些数据记录在数据存储库中。将返回的有关表结构的数据与上次返回的数据进行比较。如果不同,那么您就知道结构发生了变化。

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

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

您将根据您定义“表更改”的精确程度来监视不同的列和 INFORMATION_SCHEMA 视图。

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top