我正在尝试快速确定两组计划是否相同,并且还生成一个可以引用这些唯一计划的密钥。我最初尝试使用HASHBYTES,但很快发现你只能散列8000个字符,并且我有大量的日期时间,当连接时间超过8000时。
所以,我试图使用Checksum和Checksum_Agg,因为它们似乎是为这类东西而设计的。我知道Checksum有更高的机会生成非唯一值。但是我需要相互比较的范围/背景是如此狭窄,以为我可以逃脱它。
不幸的是,经过一些测试后我才知道我可以在4行日期时间数据中找到Checksum“碰撞”!我觉得这有点奇怪,发现碰撞的模式。
以下是演示此问题的示例脚本:
DECLARE @Rows TABLE ( [GroupId] INT, [StartDate] DATETIME, [EndDate] DATETIME ) --Group1 INSERT INTO @Rows VALUES (1, '2013-01-20 01:00:00.000', '2013-01-20 01:20:00.000') INSERT INTO @Rows VALUES (1, '2013-01-20 01:20:00.000', '2013-01-20 01:40:00.000') --INSERT INTO @Rows VALUES (1, '2013-01-20 01:40:00.000', '2013-01-20 02:00:00.000') --INSERT INTO @Rows VALUES (1, '2013-01-20 02:00:00.000', '2013-01-20 02:20:00.000') --INSERT INTO @Rows VALUES (1, '2013-01-20 02:20:00.000', '2013-01-20 02:40:00.000') --INSERT INTO @Rows VALUES (1, '2013-01-20 02:40:00.000', '2013-01-20 03:00:00.000') --Group2 INSERT INTO @Rows VALUES (2, '2013-01-21 01:00:00.000', '2013-01-21 01:20:00.000') INSERT INTO @Rows VALUES (2, '2013-01-21 01:20:00.000', '2013-01-21 01:40:00.000') --INSERT INTO @Rows VALUES (2, '2013-01-21 01:40:00.000', '2013-01-21 02:00:00.000') --INSERT INTO @Rows VALUES (2, '2013-01-21 02:00:00.000', '2013-01-21 02:20:00.000') --INSERT INTO @Rows VALUES (2, '2013-01-21 02:20:00.000', '2013-01-21 02:40:00.000') --INSERT INTO @Rows VALUES (2, '2013-01-21 02:40:00.000', '2013-01-21 03:00:00.000') SELECT [ChecksumAgg1] = CHECKSUM_AGG([CheckSum]) FROM ( SELECT [CheckSum] = CHECKSUM([StartDate], [EndDate]) FROM @Rows WHERE GroupId = 1 ) G1 SELECT [ChecksumAgg2] = CHECKSUM_AGG([CheckSum]) FROM ( SELECT [CheckSum] = CHECKSUM([StartDate], [EndDate]) FROM @Rows WHERE GroupId = 2 ) G2
结果是:
ChecksumAgg1: 5681728
ChecksumAgg2: 5681728
两个系列日期之间的唯一区别是它们相隔1天。但它们产生相同的校验和!但是只有存在偶数行。如果您取消对第1组中的INSERT和第2组中的INSERT的注释,您将获得两个不同的校验和。但是,然后再评论另一对,你会得到另一场比赛!
最后我有两个问题。我想更多地了解它是如何工作的,以及为什么这个模式似乎会影响一个非常可预测的校验和值。更重要的是,我想知道是否有更好的方法来创建一个非常大的数据集的“指纹”。我知道我不能保证这个散列是全局唯一的,但我显然需要比Checksum更好的东西。
我能够对Checksum计算进行各种操作的一种方法是在Datetime上执行HASHBYTES,然后将其提供给Checksum函数。这样,校验和被馈送的值比具有相似观察差异的一组日期更随机。但这还够吗?
编辑 - 这里只是更多背景信息。
基本上我有一个系统,它有大量的时间表数据和一个在特定时间对这些时间表感兴趣的独立系统。例如,多个用户可能会看到此复杂计划的某个部分的特定版本,并希望添加一些元数据(可能是他们的批准状态,注释或其他内容)。如果某个外部源对任何单个日期时间进行更改,则需要断开此链接,因为它不再是相同的计划!
有许多不同的系统可以对核心计划数据进行更改,这就是为什么我很难将这个问题冒充到代码级别以某种方式管理并将其“规范化”为代表每个快照的实体某种方式。我必须在一百万个地方寻找变化,然后清理任何指向时间表的东西。
答案 0 :(得分:2)
你认为所有这些校验和的东西 - 你必须做些什么来确保唯一性 - 值得麻烦吗?就个人而言,我认为只是直接比较列而不是尝试减少工作量并仅比较一个值,您将获得更好的性能(并且复杂性更低)。
另外请记住,当您开始使用时,日期时间值只是整数对,因此将校验和应用于两个值的组合可能会产生相同的值并不奇怪。例如:
SELECT CHECKSUM_AGG(x)
FROM
(
SELECT CHECKSUM(1,2)
UNION ALL
SELECT CHECKSUM(2,3)
) AS y(x);
SELECT CHECKSUM_AGG(x)
FROM
(
SELECT CHECKSUM(2,2)
UNION ALL
SELECT CHECKSUM(1,3)
) AS y(x);
结果:
----
49
----
49
所以我建议只在StartDate, EndDate
上放一个索引并完成它。你正在努力创造一种效率已经非常高效的东西,而且我认为你正在完成相反的事情。
至于密钥,只需使用IDENTITY
列或其他代理。我认为嵌套CHECKSUM_AGG(CHECKSUM(HASHBYTES(col1),HASHBYTES(col2)))
以模拟唯一性没有优势......
编辑
或者根据新要求,如果要确保数据与上次读取数据相同,只需使用ROWVERSION
列。我没有看到跟踪数百万校验和结果与跟踪rowversion或其他计算值有何不同。当你已经内置的东西做你想做的事情时,你的工作太难了......
答案 1 :(得分:1)
来自此页面的评论:
http://msdn.microsoft.com/en-us/library/ms188920.aspx
看来Checksum_Agg是使用XOR构建的。关于XOR的事情是,通过两次包含相同的数字,它们往往很容易逆转。这就解释了为什么你在偶数时才注意到它。
只要你知道XOR问题,并以混合所有比特的方式预先加扰你所提供的内容,你应该没问题。
答案 2 :(得分:0)
我遇到了这个问题。当列中的所有值都相同时,会出现这种情况。计算总和时,可能不会使用此列。