SQL Server:通过更改数据捕获和散列提高合并性能

问题描述 投票:0回答:1

今天,我正在尝试调整审核数据库的性能。我有合法的理由来跟踪行的更改,并且已经使用SQL Server 2016中的“系统版本化表”方法实现了一组表。

我的整个过程将“ RAW”数据从源系统下载到初始表中。然后,从这里开始,我进行一个MERGE流程,该流程从RAW表中获取数据,并将RAW表中的每一列与可审核的系统版本化登台表中的内容进行比较,并确定已更改的内容。然后,系统行版本控制会告诉我什么已更改,什么未更改。

这种方法的麻烦在于我的表格非常宽。其中一些具有400列或更多列。即使具有450,000条记录的表也需要花费SQL服务器大约17分钟的时间来执行MERGE操作。这确实在减慢我们解决方案的性能,而且如果我们可以加快解决方案的速度,它似乎会带来很大帮助。目前,我们有数百个表需要执行此操作。

目前,RAW和STAGE表都在ID列上建立索引。

我已经阅读了几个地方,我们可能会考虑使用CHECKSUM或HASHBYTES函数在RAW提取物中记录一个值。 (您叫什么?GUID?UUID?哈希?)。然后,我们将计算出的值与STAGE表中存在的值进行比较。但是有一个难题:许多列中经常有很多NULL值。有人建议我们将所有列类型都强制转换为相同(nvarchar(max))?,而NULL值似乎会使校验和的整个计算趋于平稳。因此,我也在代码中也编码了很多ISNULL(,'UNKNOWN')语句。

所以-是否有更好的方法来改善合并的性能?我以为可以将行更新的时间戳列作为单个值而不是校验和进行比较,但是我不确定这将通过合法的要求/审查。 Legal关注的是,行可能会在界面外部进行编辑,而列不会总是更新。我已经看到开发人员使用连接函数(如下所示)将许多列值组合在一起的方法。这似乎也需要大量代码,并且计算/转换列也很昂贵。

所以我的问题是:

  • 鉴于实际情况,我可以在这里以任何方式提高MERGE的性能吗?
  • 我应该使用校验和还是哈希字节,为什么?
  • 哪种hashbytes方法在这里最有意义? (我只是根据ID匹配权将一个RAW行与另一个STAGE行进行比较)?
  • 我是否错过了某些功能,这些功能可能会使阅读中的比较更快或更容易我已经做好了?似乎很奇怪,除了CONCAT之外,没有更好的功能可以在SQL Server中完成。
  • 我编写了以下代码,以显示我正在考虑的一些想法。有什么比我在下面写的更好的东西吗?

    DROP TABLE IF EXISTS MyTable;
    
    CREATE TABLE MyTable
        (C1 VARCHAR(10),
         C2 VARCHAR(10),
         C3 VARCHAR(10)
         );
    
    INSERT INTO MyTable
        (C1,C2,C3)
    VALUES
        (NULL,NULL,NULL),
        (NULL,NULL,3),
        (NULL,2,3),
        (1,2,3);
    
    
    SELECT
        HASHBYTES('SHA2_256',
        CONCAT(C1,'-',
               C2,'-',
               C3)) AS HashbytesValueCastWithNoNullCheck,
    
    
        HASHBYTES('SHA2_256',
        CONCAT(CAST(C1 as varchar(max)),'-',
               CAST(C2 as varchar(max)),'-',
               CAST(C3 as varchar(max)))) AS HashbytesValueCastWithNoNullCheck,
    
    
        HASHBYTES('SHA2_256',
        CONCAT(ISNULL(CAST(C1 as varchar(max)),'UNKNOWN'),'-',
               ISNULL(CAST(C2 as varchar(max)),'UNKNOWN'),'-',
               ISNULL(CAST(C3 as varchar(max)),'UNKNOWN'))) AS HashbytesValueWithCastWithNullCheck,
        CONCAT(ISNULL(CAST(C1 as varchar(max)),'UNKNOWN'),'-',
               ISNULL(CAST(C2 as varchar(max)),'UNKNOWN'),'-',
               ISNULL(CAST(C3 as varchar(max)),'UNKNOWN')) AS StringValue,
        CONCAT(C1,'-',C2,'-',C3) AS ConcatString,
        C1,
        C2,
        C3
    FROM
        MyTable;
    
    '''
    
sql-server tsql merge dimensional-modeling
1个回答
0
投票
鉴于实际情况,我可以在这里以任何方式提高MERGE的性能吗?
您应该进行测试,但为每行存储一个哈希,为新行计算哈希,并基于(key,hash)进行比较,比比较每一列都要便宜。

我应该使用校验和还是哈希字节,为什么?

HASHBYTES具有丢失更改的可能性要低得多。就像使用CHECKSUM一样,您最终可能会错过一两个更改,而使用HASHBYTES则可能永远不会错过更改。在这里查看备注:BINARY_CHECKSUM

我是否错过了某些功能,这些功能可能使我在阅读时可以更快或更容易地进行比较?

没有没有比较多列的特殊方法。

有什么比我在下面写的更好的东西吗?

您肯定应该替换为空,否则行(1,null,'A')(1,'A',null)将获得相同的哈希值。并且您应该用不会在任何列中显示为值的值替换空值和定界。而且,如果您有Unicode文本,则转换为varchar可能会删除某些更改,因此使用nvarchar更为安全。例如:

HASHBYTES('SHA2_256', CONCAT(ISNULL(CAST(C1 as nvarchar(max)),N'~'),N'|', ISNULL(CAST(C2 as nvarchar(max)),N'~'),N'|', ISNULL(CAST(C3 as nvarchar(max)),N'~'))) AS HashbytesValueWithCastWithNullCheck

© www.soinside.com 2019 - 2024. All rights reserved.