【问题标题】:How can I use hashbytes like checksum?如何使用像校验和这样的哈希字节?
【发布时间】:2015-02-18 10:58:02
【问题描述】:

在 SQL Server 中,我们可以使用“校验和”轻松地在整行上生成哈希:

select 
checksum(*), *    
from mytable

有没有办法使用 hashbytes 函数做同样的事情? 比如:

select 
hashbytes('md5', *), *    
from mytable

【问题讨论】:

    标签: sql-server hash checksum


    【解决方案1】:

    恐怕不容易。在大多数情况下,你不应该真的想要。但如果必须,为每一行生成一个 XML 文档并对 XML 文档进行散列处理可能是最简单的方法:

    SELECT  HASHBYTES('MD5', X.value)
    FROM    Data
    CROSS APPLY (
        SELECT value = 
            CAST((SELECT Data.* FROM   (SELECT 1) AS X (y) FOR XML AUTO) AS VARCHAR(MAX))
    ) AS X
    

    编辑:我做了一些测试,应用CAST(... AS VARCHAR(MAX)),就像我在上面更新的语句中所做的那样,性能提高了大约 15%。更重要的是,它可以防止宽表上的截断错误。即使在此修复之后,您自己连接列仍然快 15% 左右。使用 CONCAT()(可从 MSSQL 2012 获得)函数可以让您的生活更轻松一些,因为您可以省略对每列应用 ISNULL 和 CAST 函数。

    【讨论】:

    • 聪明,它还具有针对列内容重叠的内置保护。不过,它的性能是否可以接受是另一回事。
    【解决方案2】:

    如果写出列没有异议,您可以简单地连接列并散列:

    SELECT HASHBYTES('md5', 
        ISNULL(CONVERT(VARBINARY(MAX), column1), 0x) +
        ISNULL(CONVERT(VARBINARY(MAX), column2), 0x) + 
        ...
    )
    

    从 SQL Server 2012 开始,我们可以使用CONCAT 更紧凑地实现相同的目标(感谢@MWillemse 的提示):

    SELECT HASHBYTES('md5', CONCAT(column1, column2, ...))
    

    请注意,如果您的列“相同”,这可能会导致冲突:散列AA,BB,CC 产生与AAB,BBC,C 甚至AABBCC,NULL,NULL 相同的结果。如果这是一个问题,您必须设计自己的散列方案以最小化这种可能性(例如,通过在散列中包含列名)。此外,这是一个二进制校验和:散列 A,B,Ca,b,c 不同。同样,如果这是一个问题,您必须在散列之前调整数据 (UPPER)。

    最后,MD5 不再被认为是加密安全的,因此仅将其用于校验和索引等需要比CHECKSUM 更少的冲突概率的事情。如果你需要一行的加密签名,那就太简单了。

    【讨论】:

    • 可能值得在列之间添加分隔符,例如'|~'。 +1 使用 CONCAT
    猜你喜欢
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 2010-10-02
    相关资源
    最近更新 更多