checksum_agg 似乎只是将所有行的 binary_checksum 的结果相加。尽管每一行都发生了变化,但两个校验和的总和没有变化(即 17+32 = 16+33)。这并不是检查更新的真正标准,但我能提出的建议如下:
- 不使用
checksum_agg
,而是将校验和连接成一个分隔字符串,并按照SELECT binary_checksum(*) + ',' FROM MyTable FOR XML PATH('')
. 要检查和存储的字符串要长得多,但误报比较的可能性要小得多。
- 不使用内置校验和例程,而是使用 HASHBYTES 计算 8000 字节块中的 MD5 校验和,并将结果异或。这将为您提供更具弹性的校验和,尽管仍然不是万无一失的(即仍然可能获得错误匹配,但可能性很小)。我将粘贴我在下面编写的 HASHBYTES 演示代码。
- 最后一个选项,也是绝对最后的手段,是以 XML 格式实际存储表表,并进行比较。这确实是您可以绝对确定没有错误匹配的唯一方法,但不可扩展并且涉及存储和比较大量数据。
每种方法,包括您开始使用的方法,都有利有弊,数据大小和处理要求对准确性有不同程度的影响。根据您需要的准确度级别,使用适当的选项。获得 100% 准确率的唯一方法是存储所有表数据。
或者,您可以向每个表添加一个 date_modified 字段,该字段使用 after insert 和 update 触发器设置为 GetDate()。你可以做到SELECT COUNT(*) FROM #test WHERE date_modified > @date_last_checked
。这是一种更常见的检查更新的方法。这个的缺点是无法跟踪删除。
另一种方法是创建一个修改后的表,其中包含 table_name (VARCHAR) 和 is_modified (BIT) 字段,其中包含您希望跟踪的每个表的一行。使用插入、更新和删除触发器,针对相关表的标志设置为 True。当您运行计划时,您检查并重置 is_modified 标志(在同一事务中) - 沿着SELECT @is_modified = is_modified, is_modified = 0 FROM tblModified
以下脚本生成三个结果集,每个结果集都与此响应中前面的编号列表相对应。我已经在 SELECT 语句之前评论了哪个输出对应于哪个选项。要查看输出是如何得出的,您可以通过代码向后工作。
-- Create the test table and populate it
CREATE TABLE #Test (
f1 INT,
f2 INT
)
INSERT INTO #Test VALUES(1, 1)
INSERT INTO #Test VALUES(2, 0)
INSERT INTO #Test VALUES(2, 1)
/*******************
OPTION 1
*******************/
SELECT CAST(binary_checksum(*) AS VARCHAR) + ',' FROM #test FOR XML PATH('')
-- Declaration: Input and output MD5 checksums (@in and @out), input string (@input), and counter (@i)
DECLARE @in VARBINARY(16), @out VARBINARY(16), @input VARCHAR(MAX), @i INT
-- Initialize @input string as the XML dump of the table
-- Use this as your comparison string if you choose to not use the MD5 checksum
SET @input = (SELECT * FROM #Test FOR XML RAW)
/*******************
OPTION 3
*******************/
SELECT @input
-- Initialise counter and output MD5.
SET @i = 1
SET @out = 0x00000000000000000000000000000000
WHILE @i <= LEN(@input)
BEGIN
-- calculate MD5 for this batch
SET @in = HASHBYTES('MD5', SUBSTRING(@input, @i, CASE WHEN LEN(@input) - @i > 8000 THEN 8000 ELSE LEN(@input) - @i END))
-- xor the results with the output
SET @out = CAST(CAST(SUBSTRING(@in, 1, 4) AS INT) ^ CAST(SUBSTRING(@out, 1, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 5, 4) AS INT) ^ CAST(SUBSTRING(@out, 5, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 9, 4) AS INT) ^ CAST(SUBSTRING(@out, 9, 4) AS INT) AS VARBINARY(4)) +
CAST(CAST(SUBSTRING(@in, 13, 4) AS INT) ^ CAST(SUBSTRING(@out, 13, 4) AS INT) AS VARBINARY(4))
SET @i = @i + 8000
END
/*******************
OPTION 2
*******************/
SELECT @out