【发布时间】:2015-02-18 10:58:02
【问题描述】:
在 SQL Server 中,我们可以使用“校验和”轻松地在整行上生成哈希:
select
checksum(*), *
from mytable
有没有办法使用 hashbytes 函数做同样的事情? 比如:
select
hashbytes('md5', *), *
from mytable
【问题讨论】:
标签: sql-server hash checksum
在 SQL Server 中,我们可以使用“校验和”轻松地在整行上生成哈希:
select
checksum(*), *
from mytable
有没有办法使用 hashbytes 函数做同样的事情? 比如:
select
hashbytes('md5', *), *
from mytable
【问题讨论】:
标签: sql-server hash checksum
恐怕不容易。在大多数情况下,你不应该真的想要。但如果必须,为每一行生成一个 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 函数。
【讨论】:
如果写出列没有异议,您可以简单地连接列并散列:
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,C 与 a,b,c 不同。同样,如果这是一个问题,您必须在散列之前调整数据 (UPPER)。
最后,MD5 不再被认为是加密安全的,因此仅将其用于校验和索引等需要比CHECKSUM 更少的冲突概率的事情。如果你需要一行的加密签名,那就太简单了。
【讨论】: