今天,我正在尝试调整审核数据库的性能。我有合法的理由来跟踪行的更改,并且已经使用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关注的是,行可能会在界面外部进行编辑,而列不会总是更新。我已经看到开发人员使用连接函数(如下所示)将许多列值组合在一起的方法。这似乎也需要大量代码,并且计算/转换列也很昂贵。
所以我的问题是:
我编写了以下代码,以显示我正在考虑的一些想法。有什么比我在下面写的更好的东西吗?
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;
'''
您应该进行测试,但为每行存储一个哈希,为新行计算哈希,并基于(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