7

我有一个复杂的查询,它使用了很多二进制校验和函数,当我用一些测试数据对两个不同的记录进行测试时,它实际上返回了相同的校验和值。请在下面找到我使用的测试数据

SELECT BINARY_CHECKSUM(16   ,'EP30461105',1) AS BinaryCheckSumEx UNION ALL
SELECT BINARY_CHECKSUM(21   ,'EP30461155',1) AS BinaryCheckSumEx

现在我正在尝试将 HASHBYTES 函数与“MD5”算法一起使用,我可以确定获得唯一记录,但现在我担心的是在当前查询中我使用“校验和”值加入我的“合并”语句寻找新的记录。由于“HashBytes”返回给我 Varbinary 数据类型,当我用“HashByte”字段替换连接条件时,我可以预期多少性能开销。

SELECT HASHBYTES('MD5', CONCAT(Col1,Col2,Col3,Col4,..))

此外,我需要为多个列创建散列,在这种情况下,我需要一个额外的 Concat 函数,这会对我的性能产生额外的开销。

4

1 回答 1

6

以下是选项:

  1. 使用哈希索引作为 VARBINARY

  2. 使用 BINARY_CHECKSUM 和 CHECKSUM

    • 这很好,但问题是校验和重复的可能性很高,当你用谷歌搜索时,你会发现很多人都有这个问题。

但是,校验和不会改变的可能性很小。因此,我们不建议使用 CHECKSUM 来检测值是否已更改,除非您的应用程序可以容忍偶尔丢失更改。考虑改用 HashBytes。当指定 MD5 哈希算法时,HashBytes 对两个不同的输入返回相同结果的概率远低于 CHECKSUM。

来源:https ://msdn.microsoft.com/en-us/library/ms189788(v=SQL.100).aspx

  1. 将 HASBYTES 转换为 BIGINT 并在其上有索引
    • 这不是一个好主意

考虑到 BIGINT 只有 8 个字节,但所有哈希算法(甚至 MD5)都大于 8 个字节(MD5 = 16 个字节,SHA1 = 20,SHA2_256 = 32 和 SHA2_512 = 64)。并且将大于 8 字节的二进制值转换为 BIGINT 会默默地截断这些值。因此,您会失去准确性并增加误报的发生率。以下查询显示了这种行为:

SELECT CONVERT(BIGINT, 0xFFFFFFFFFFFFFF),      --  7 bytes = 72057594037927935
       CONVERT(BIGINT, 0xFFFFFFFFFFFFFFFF),    --  8 bytes = -1
       CONVERT(BIGINT, 0xFFFFFFFFFFFFFFFFFF),  --  9 bytes = -1
       CONVERT(BIGINT, 0xFFFFFFFFFFFFFFFFFFFF) -- 10 bytes = -1

资料来源:https ://dba.stackexchange.com/questions/154945/index-maintenance-for-varbinary

  1. 将 HASHBYTES 转换为 VARCHAR 并在其上有索引
    • 这是不错的选择
    • 你有两个选择:

a) 如果您使用的是 SQL 2008 或更高版本

SELECT CONVERT(NVARCHAR(32),HashBytes('MD5', CONTENT),2)

b) 如果您使用的是 SQL 2005

SELECT SUBSTRING(master.dbo.fn_varbintohexstr(HashBytes('MD5', CONTENT)), 3, 32)

PS:如果您想知道应该使用哪种哈希算法:

MD5 = 16 bytes
SHA1 = 20 bytes
SHA2_256 = 32 bytes
SHA2_512 = 64 bytes

在此处输入图像描述

来源:https ://blogs.msdn.microsoft.com/sqlsecurity/2011/08/26/data-hashing-in-sql-server/

对于第二个问题,您应该使哈希列保持不变,以避免对运行每个查询的影响。

于 2017-06-20T14:41:32.310 回答