2016-09-15 104 views
1

我们试图在ETL过程中实现变更检测。Sql - 批量加密哈希生成

所以我们决定要使用

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 

对于70万次的记录和大约140列的表格(我们还没有确定改变列)的加密哈希,之前的查询运行约一个半小时我们取消了它。

无论如何,除了减少查询次数,我们可以改进这个吗?

回答

1

一些事情。如果HASH列的数据类型为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的开销)。

+0

看起来非常好。我会放弃它并让你知道。关于CHECKSUM的使用,提到的文档可能在值更改时不会更改,因此不适用于更改检测。这是我们的第一选择。 – frostymarvelous

+0

我认为这只是一个CYA,因为任何哈希算法都会碰撞(包括MD5)。您也可以在表格中添加一个“rowversion”列,然后完全跳过这个计算。 –

+0

由于我们使用ssis从oracle数据库中提取数据,因此Rowversion不起作用。 – frostymarvelous

1

与[本图尔]已经说过的一样,我也倾向于仅仅依靠BINARY_CHECKSUM(),因为它的易用性。 我会同意这个函数返回“但是一个int”,它是8个字节,而例如MD5将返回一个varbinary(16),它是字节的两倍,所以你得到了'result-空间“意味着你最终会碰撞的机会非常小。但偏执我想补充一点,即使如此,MD5值的精确匹配并不意味着你也有相同的(输入)值!

诚实地说,我只是使用函数来消除分歧。如果校验和(或散列)的结果不同,那么你可以100%确定这些值也是不同的。如果它们是相同的,那么你仍然应该检查整个源值以查看是否不存在'错误匹配'。

你的用例似乎是另一种方式:你想通过查看哈希码来找到那些不同的哈希码,通过消除相同的哈希码来缩短后者。说实话,我并不喜欢这种方法,只是因为你冒着碰撞的风险碰撞,导致登台表中的'更改'记录得到与旧登记表完全相同的哈希值,因此在你想要时会被忽略复制更改。同样,机会是令人难以置信的小,但就像我说的,我是偏执狂,当谈到这个=)

如果你希望仍然继续向下这条赛道,一些言论:

  • HashBytes仅支持8000字节的输入。鉴于XML语法增加的开销可能会与140列遇到麻烦
  • 我没有看到否则写入表之前的任何(良好的)理由的HashBytes的东西转换结果
  • 虽然FOR XML相当快,不会CONCAT一样快,同时导致“较小”的结果(比较点1)?我会同意,它会带来自己的一系列问题,例如field1,field2,field3是“hello”,“world”“”会导致与“hello”,“”,“world”= /通过CONCAT - 在每个领域的 - 的LEN()太...不知道我们还有多少增益=)
  • 我猜你已经拥有了它,但有没有索引,最好是独特的在登台表中的customer_no字段上群集?
+0

感谢您提出的非常有效的观点。我们实际上决定使用concat,并限制我们想要跟踪的列数(也确保我们每次都保持订单)。我们不是使用LEN来划分每一列。我们将放弃转换为varchar,转而使用原始字节,因为它已经被多次提升。 – frostymarvelous