在SSIS中查找更新的记录-哈希还是不哈希?

Joh*_*ohn 0 ssis

我正在使用SSIS将数据从DB2数据库中的表迁移到我们的SQL Server数据库。我从中提取数据的表中包含大量数据-少于100,000条记录;但是,它也有46列。

我只想更新需要更新的行,因此得出的结论是,我可以使用“查找转换”并检查所有46列,然后重定向“无匹配项”以在SQL表上进行更新。或者,我可以在数据任务流的开头读取数据后对数据集中的每一行进行哈希处理,然后在以后确定行是否相等时使用哈希值作为比较。

我的问题是:哪种方法更好?我喜欢对它们进行哈希处理,但是我不确定这是否是最佳选择。有没有人愿意分享任何智慧的明珠?

bil*_*nkc 5

为什么不同时?

一般来说,进行增量加载时需要寻找两件事:是否存在?如果存在,请进行更改。如果只有一列,那是微不足道的。当要检查的列很多时,这会变得很痛苦,尤其是如果您正在使用SSIS映射所有这些列和/或不得不担心NULL。

我通过作弊解决了多列问题-我在所有表中创建了两列:HistoricalHashKey和ChangeHashKey。历史哈希密钥将是所有业务密钥。更改哈希键是所有其余的实质性列(我将排除诸如审计列之类的东西)。我们没有将连接的值直接存储在哈希列中。取而代之的是,“我们要把所有的东西都算掉”,并应用一种称为SHA-1的哈希算法。该算法将获取所有输入列,并返回20字节的输出。

使用此方法有三个警告。每次必须以相同顺序连接列。这些将区分大小写。尾随空间很大。而已。

在表中,您将这两列添加为binary(20)NOT NULL。

设定

您的控制流程如下所示

控制流

你的数据流是这样的

数据流

OLESRC增量数据

(假设我来自Adventureworks2014,Production.Product。)我将使用SQL Server 2012+中的CONCAT函数,因为它会将所有数据类型提升为字符串,并且是NULL安全的。

SELECT
    P.ProductID
,   P.Name
,   P.ProductNumber
,   P.MakeFlag
,   P.FinishedGoodsFlag
,   P.Color
,   P.SafetyStockLevel
,   P.ReorderPoint
,   P.StandardCost
,   P.ListPrice
,   P.Size
,   P.SizeUnitMeasureCode
,   P.WeightUnitMeasureCode
,   P.Weight
,   P.DaysToManufacture
,   P.ProductLine
,   P.Class
,   P.Style
,   P.ProductSubcategoryID
,   P.ProductModelID
,   P.SellStartDate
,   P.SellEndDate
,   P.DiscontinuedDate

,   P.rowguid
,   P.ModifiedDate

-- Hash my business key(s)
,   CONVERT(binary(20), HASHBYTES('MD5',
            CONCAT
            (
            -- Having an empty string as the first argument
            -- allows me to simplify building of column list
                ''
            ,   P.ProductID
            )
        )
    ) AS HistoricalHashKey

-- Hash the remaining columns
,   CONVERT(binary(20), HASHBYTES('MD5',
            CONCAT
            (      
                ''
            ,   P.Name
            ,   P.ProductNumber
            ,   P.MakeFlag
            ,   P.FinishedGoodsFlag
            ,   P.Color
            ,   P.SafetyStockLevel
            ,   P.ReorderPoint
            ,   P.StandardCost
            ,   P.ListPrice
            ,   P.Size
            ,   P.SizeUnitMeasureCode
            ,   P.WeightUnitMeasureCode
            ,   P.Weight
            ,   P.DaysToManufacture
            ,   P.ProductLine
            ,   P.Class
            ,   P.Style
            ,   P.ProductSubcategoryID
            ,   P.ProductModelID
            ,   P.SellStartDate
            ,   P.SellEndDate
            ,   P.DiscontinuedDate
            )
        )
    ) AS ChangeHashKey
FROM
    Production.Product AS P;
Run Code Online (Sandbox Code Playgroud)

LKP检查存在

该查询将从我们的参考表中拉回存储的HistoricalHashKey和ChangeHashKey。

SELECT
    DP.HistoricalHashKey
,   DP.ChangeHashKey
FROM
    dbo.DimProduct AS DP;
Run Code Online (Sandbox Code Playgroud)

在这一点上,比较HistoricalHashKeys以确定行是否存在很简单。如果匹配,我们想将ChangeHashKey拉回到我们的数据流中。按照约定,我将此名称命名为lkp_ChangeHashKey,以区别于源ChangeHashKey。

CSPL变化检测

条件拆分也得到了简化。两个“更改哈希”键匹配(不更改)或不匹配(已更改)。该表达将是

ChangeHashKey == lkp_ChangeHashKey
Run Code Online (Sandbox Code Playgroud)

OLE_DST暂存更新

而不是使用OLE DB命令,而是创建一个专用表来保存需要更新的行。OLE DB Command不能很好地扩展,因为它在后台发出单例更新命令。

SQL执行基于集合的更新

数据流完成后,所有需要更新的数据都将在我们的登台表中。该执行SQL任务只是更新与我们业务键匹配的现有数据。

UPDATE
    TGT
SET
    Name = SRC.name
,   ProductNumber = SRC.
FROM
    dbo.DimProduct AS TGT
    INNER JOIN
        Stage.DimProduct AS SRC
        ON SRC.HistoricalHashKey = TGT.HistoricalHashKey;
        -- If clustered on a single column and table is large, this will yield better performance
        -- ON SRC.DimProductSK = TGT.DimProductSK;
Run Code Online (Sandbox Code Playgroud)

从评论

既然有光泽,为什么要使用专用INSERTUPDATE声明MERGE?除了不容易记住语法外,SQL Server实现还可能会产生某些意外的后果。它们可能是极端的案例,但我宁愿不使用我提供的解决方案来解决它们。显式INSERT和UPDATE语句为我的解决方案提供了我想要和需要的细粒度控制。我喜欢SQL Server,认为这是一个很棒的产品,但是它们奇怪的语法加上已知的错误使我无法在认证考试之外的任何地方使用MERGE。