【问题标题】:Why do these Datetime values return the same Checksum & Checksum_Agg? How can I make it more unique?为什么这些 Datetime 值返回相同的 Checksum 和 Checksum_Agg?我怎样才能让它更独特?
【发布时间】:2013-01-05 04:52:04
【问题描述】:

我正在尝试快速确定两组时间表是否相同,并生成一个可以引用这些独特时间表的密钥。我最初尝试使用 HASHBYTES,但很快发现您只能散列 8000 个字符,而且我有大量的日期时间,它们连接时超过 8000。

所以,我尝试使用 Checksum 和 Checksum_Agg,因为它们似乎是为这类事情而设计的。我知道校验和更有可能生成非唯一值。但是我需要将它们相互比较的范围/背景太窄了,我想我可以侥幸逃脱。

不幸的是,经过一些测试后,我了解到我可以在 4 行日期时间数据中找到校验和“冲突”!我觉得这有点奇怪,并发现了碰撞的模式。

下面是一个演示该问题的示例脚本:

声明@Rows 表 ( [GroupId] 整数, [开始日期] 日期时间, [结束日期] DATETIME ) --Group1 插入@Rows 值(1、'2013-01-20 01:00:00.000'、'2013-01-20 01:20:00.000') 插入@Rows 值(1,'2013-01-20 01:20:00.000','2013-01-20 01:40:00.000') --INSERT INTO @Rows 值 (1, '2013-01-20 01:40:00.000', '2013-01-20 02:00:00.000') --INSERT INTO @Rows 值 (1, '2013-01-20 02:00:00.000', '2013-01-20 02:20:00.000') --INSERT INTO @Rows 值 (1, '2013-01-20 02:20:00.000', '2013-01-20 02:40:00.000') --INSERT INTO @Rows 值 (1, '2013-01-20 02:40:00.000', '2013-01-20 03:00:00.000') --Group2 插入@Rows 值(2、'2013-01-21 01:00:00.000'、'2013-01-21 01:20:00.000') 插入@Rows 值(2、'2013-01-21 01:20:00.000'、'2013-01-21 01:40:00.000') --INSERT INTO @Rows 值 (2, '2013-01-21 01:40:00.000', '2013-01-21 02:00:00.000') --INSERT INTO @Rows 值 (2, '2013-01-21 02:00:00.000', '2013-01-21 02:20:00.000') --INSERT INTO @Rows 值 (2, '2013-01-21 02:20:00.000', '2013-01-21 02:40:00.000') --INSERT INTO @Rows 值 (2, '2013-01-21 02:40:00.000', '2013-01-21 03:00:00.000') 选择 [ChecksumAgg1] = CHECKSUM_AGG([CheckSum]) 从 ( 选择 [校验和] = 校验和([开始日期],[结束日期]) 来自@Rows 其中 GroupId = 1 ) G1 选择 [ChecksumAgg2] = CHECKSUM_AGG([CheckSum]) 从 ( 选择 [校验和] = 校验和([开始日期],[结束日期]) 来自@Rows 其中 GroupId = 2 ) G2

结果是:

ChecksumAgg1:5681728

ChecksumAgg2:5681728

这两个日期系列之间的唯一区别是它们相隔 1 天。但是它们会生成相同的校验和!但仅当存在 偶数 行时。如果您取消注释 Group 1 中的 INSERT 和 Group 2 中的一个 INSERT,您将获得两个不同的校验和。但是然后取消注释另一对,您将获得另一对!


最后我有两个问题。我很想更多地了解它是如何工作的,以及为什么这种模式似乎会影响一个相当可预测的校验和值。更重要的是,我想知道是否有更好的方法来创建大量数据的“指纹”。我知道我不能保证这个哈希是全球唯一的,但我显然需要比校验和更好的东西。

我能够对校验和计算进行某种技巧的一种方法是在 Datetime 上执行 HASHBYTES,然后将其提供给 Checksum 函数。通过这种方式,校验和被提供的值比一组具有相似外观差异的日期看起来更随机。但这样就够了吗?


编辑 - 这里只是更多的上下文。

基本上,我有一个拥有大量日程数据的系统和一个在特定时间对这些日程感兴趣的单独系统。例如,多个用户可能会看到这个复杂时间表的某个部分的特定版本,并希望添加一些元数据(可能是他们的批准状态、注释或其他内容)。如果某些外部来源对任何单个日期时间进行了更改,则需要断开此链接,因为它不再是相同的时间表!

有许多不同的系统可以对核心计划数据进行更改,这就是为什么我很难将这种担忧提升到代码级别,以便以某种方式对其进行管理和“规范化”为代表每个快照的实体某种方式。我必须在一百万个地方安装钩子来监听变化,然后清理任何指向时间表的东西。

【问题讨论】:

    标签: sql-server hash checksum


    【解决方案1】:

    你认为所有这些校验和的东西 - 考虑到你还必须做些什么来确保唯一性 - 值得麻烦吗?我个人认为,直接比较列而不是尝试减少工作并只比较一个值,您将获得更好的性能(并且复杂性更低)。

    还请记住,当您深入了解日期时间值时,它只是整数对,因此将校验和应用于两个值的组合可能会导致相同的值,这并不奇怪。例如:

    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 或其他计算值有何不同。当已经有内置的东西可以做你想做的事情时,你工作太努力了......

    【讨论】:

    • 感谢您的回复。您对索引绝对正确。不幸的是,我需要以某种方式“引用”这些数据集并添加一些元数据,因此我需要某种 ID,以便将其存储在另一个表中。我将用我无法在此评论中包含的更多信息更新问题。
    【解决方案2】:

    来自本页的评论:

    http://msdn.microsoft.com/en-us/library/ms188920.aspx

    看来 Checksum_Agg 是使用 XOR 构建的。关于 XOR 的问题是,它们往往很容易通过包含两次相同的数字来逆转。这就解释了为什么你只在天平时才注意到它。

    只要您了解 XOR 问题,并以混合所有位的方式预先打乱您输入的内容,您应该没问题。

    【讨论】:

    • 有趣!看起来我也偶然发现了该评论提出的相同建议。也许首先使用MD5'ing它是要走的路。谢谢!
    【解决方案3】:

    我也遇到过这个问题。当您在列中的所有值都相同时,就会出现这种情况。计算总和时可能不占用此列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-22
      • 1970-01-01
      • 1970-01-01
      • 2019-06-13
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      相关资源
      最近更新 更多