Sql - 批量加密哈希生成

时间:2016-09-15 18:09:34

标签: 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 customer_demographics_staging a

对于包含700k记录和大约140列的表(我们尚未确定更改列),查询会在我们取消之前运行大约半小时。

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

2 个答案:

答案 0 :(得分: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的开销)。

答案 1 :(得分:1)

与[Ben Thul]已经说过的内容一致,我也倾向于依赖BINARY_CHECKSUM(),因为它易于使用。 我同意这个函数返回"但是一个int"这是8个字节,而例如MD5将返回一个varbinary(16),这是字节的两倍,所以你得到'结果空间'的结果(不是双!)。这意味着你最终会遇到极小的碰撞机会。但是偏执我想补充说即使如此,MD5值的精确匹配并不意味着你也有相同的(输入)值!

老实说,我只使用这个功能来消除差异。如果校验和(或散列)的结果不同,那么您可以100%确定值也是不同的。如果它们相同,那么您仍应完整检查源值,以查看是否存在“错误匹配”。

您的用例似乎是另一种方式:您希望通过仅查看哈希码来消除那些相同的并且通过短切后者来找到不同的用例。说实话,我并不是这种方法的粉丝只是因为你冒着碰撞的风险导致了一次变化。在登台表中记录以获得与旧登记表完全相同的哈希值,因此当您要复制更改时将被忽略。再一次,机会非常小,但就像我说的那样,当谈到这个时,我是偏执狂=)

如果您希望继续沿着这条赛道走下去,请注意:

  • HashBytes仅支持8000字节的输入。考虑到XML语法添加的开销,您可能会遇到这些140列的问题
  • 在将HashBytes的结果写入表格之前,我没有看到任何(好)理由将其转换为其他内容
  • 虽然FOR XML速度相当快,但CONCAT CONCAT同样快,但同时会导致LEN()变小。结果(参见第1点)?我同意它会带来一系列问题,例如field1,field2,field3是" hello"," world" ""会导致和#34;你好","","世界" = /您可以通过customer_no - 每个字段的imageButton.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_UP){ // Do what you want return true; } return false; } }); 来解决这个问题...不确定我们已经离开了多少收益=)
  • 我猜你已经拥有它了,但是在登台表的{{1}}字段中是否有索引,最好是唯一的和群集的?