Sql-批量加密哈希生成
我们正在尝试在我们的ETL过程中实现变更检测 所以我们决定使用Sql-批量加密哈希生成,sql,sql-server,query-optimization,Sql,Sql Server,Query Optimization,我们正在尝试在我们的ETL过程中实现变更检测 所以我们决定使用 SET a.[HASH] = (SELECT master.dbo.fn_varbintohexsubstring(0, HashBytes('md5', (SELECT TOP 1 * FROM customer_demographics_staging b WHERE b.customer_no = a.customer_no FOR XML RAW)), 1, 0)) FROM cus
SET a.[HASH] = (SELECT
master.dbo.fn_varbintohexsubstring(0, HashBytes('md5', (SELECT TOP 1 * FROM customer_demographics_staging b WHERE b.customer_no = a.customer_no FOR XML RAW)), 1, 0))
FROM customer_demographics_staging a
对于一个有700k条记录和大约140列的表(我们还没有确定更改的列),查询运行了大约半个小时,然后我们取消了它
不管怎样,除了减少查询数量,我们还可以改进这一点吗 有几件事。如果
散列
列的数据类型是varbinary(20)
,则无需将MD5散列转换为字符串;只需存储散列字节。不过,为了达到这个目的,如果您想使用加密哈希来检测更改,我会使用内联表值函数来获取它。下面是我使用AdventureWorks拼凑的一个示例:
ALTER TABLE [HumanResources].[Employee] ADD [Hash] VARBINARY(20) NULL;
GO
CREATE FUNCTION dbo.CalculateHash(@EmployeeID AS INT)
RETURNS TABLE
AS
RETURN
SELECT e.[BusinessEntityID], HASHBYTES('md5', (
SELECT *
FROM [HumanResources].[Employee] AS [e2]
WHERE [e2].[BusinessEntityID] = e.[BusinessEntityID]
FOR XML RAW
)) AS [Hash]
FROM [HumanResources].[Employee] AS [e]
WHERE [e].[BusinessEntityID] = @EmployeeID
go
SELECT TOP 10 [e].*, ch.[Hash]
FROM [HumanResources].[Employee] AS [e]
CROSS APPLY dbo.[CalculateHash]([e].[BusinessEntityID]) AS [ch]
GO
也就是说,如果是我的话,我根本不会为MD5操心,只使用
CHECKSUM()
函数(可能作为表中的持久计算列)。它支持以本机方式获取多个列(因此不会产生将行序列化为XML的开销)。与[Ben Thul]已经说过的一样,我也倾向于依赖于二进制校验和()
,因为它易于使用。
我同意这个函数返回8字节的“但是一个int”,而例如MD5将返回一个两倍于字节数的varbinary(16),这样你就得到了“结果空间”的平方(而不是双精度!),这意味着你最终发生冲突的机会要小得多。但偏执狂我想补充一点,即使如此,MD5值的精确匹配并不意味着您也有相同的(输入)值
老实说,我使用该函数只是为了消除差异。如果校验和(或散列)的结果不同,则可以100%确定值也不同。如果它们是相同的,那么您仍然应该检查源值的整体,以查看是否没有“假匹配”
您的用例似乎是另一种方式:您希望通过删除相同的用例来找到不同的用例,并通过只查看哈希代码来缩短后者。老实说,我不喜欢这种方法,因为您可能会遇到冲突,导致暂存表中的“已更改”记录获得与旧记录完全相同的哈希值,从而在复制更改时被忽略。再说一次,机会非常小,但正如我所说,在这个问题上,我是偏执狂=)
如果您希望继续沿着这条路走下去,请注意:
仅支持8000字节的输入。考虑到XML语法增加的开销,您可能会在处理这140列时遇到麻烦HashBytes
- 在将
的结果写入表之前,我看不出有任何(好的)理由将其转换为其他内容HashBytes
- 虽然XML的
速度非常快,但是
是否也同样快,同时会产生“更小”的结果(参见第1点)?我同意,它带来了它自己的一系列问题,比如当field1、field2、field3是“hello”时,“world”将产生与“hello”、“world”相同的结果,你可以通过CONCAT
-同时处理每个字段的CONCAT
LEN()。。。不确定我们还剩下多少收益=)
- 我猜您已经有了它,但是在staging表中的
字段上是否有索引,最好是唯一的和聚集的customer\u no
rowversion
列,并完全跳过计算。rowversion将无法工作,因为我们正在使用ssis从oracle数据库提取数据。感谢您提出的非常有效的观点。实际上,我们决定使用concat,并限制要跟踪的列数(同时确保每次都保持顺序)。我们不使用LEN,而是对每一列进行分隔。我们将放弃对varchar的转换,转而使用原始字节,因为它被多次提升。