【问题标题】:Finding updated records in SSIS -- to hash or not to hash?在 SSIS 中查找更新的记录——散列还是不散列?
【发布时间】:2016-06-17 15:49:03
【问题描述】:

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

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

我的问题是:走哪条路更好?我喜欢散列它们,但我不确定这是否是最好的方法。有没有人想分享任何智慧的珍珠?

【问题讨论】:

    标签: ssis


    【解决方案1】:

    为什么不两者兼而有之?

    一般来说,我们在进行增量加载时会寻找两件事:这是否存在?如果存在,是否已更改。如果只有一列,那是微不足道的。当有很多列要检查时,这会变得相当痛苦,尤其是如果您使用 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;
    

    LKP 检查存在

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

    SELECT
        DP.HistoricalHashKey
    ,   DP.ChangeHashKey
    FROM
        dbo.DimProduct AS DP;
    

    此时,通过比较HistoricalHashKeys 来判断该行是否存在就很简单了。如果我们匹配,我们希望将 ChangeHashKey 拉回我们的数据流中。按照惯例,我将此命名为 lkp_ChangeHashKey 以区别于源 ChangeHashKey。

    CSPL 变更检测

    条件拆分也被简化了。两个 Change Hash 键匹配(无更改)或不匹配(已更改)。该表达式将是

    ChangeHashKey == lkp_ChangeHashKey
    

    OLE_DST 分段更新

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

    SQL 执行基于集合的更新

    数据流完成后,所有需要更新的数据都会在我们的暂存表中。这个 Execute SQL Task 只是更新我们的业务键匹配的现有数据。

    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;
    

    来自 cmets

    既然我们有闪亮的MERGE,为什么我要使用专用的INSERTUPDATE 语句?除了不那么容易记住语法之外,SQL Server 实现还可以有一些...unintended consequences。它们可能是角落ish 案例,但我宁愿不要在我提供的解决方案中遇到它们。显式 INSERT 和 UPDATE 语句为我提供了我在解决方案中想要和需要的细粒度控制。我喜欢 SQL Server,认为它是一个很棒的产品,但它们奇怪的语法加上已知的错误使我无法在任何地方使用 MERGE,除非是认证考试。

    【讨论】:

    • 哇!这是一个惊人的答案。我对 SSIS 还是很陌生,但你在解释整个过程方面做得很好。很棒的反应!
    • 对@billinkc 的问题 - 为什么在 SQL 执行基于集合的更新 步骤中更喜欢 SQL 更新而不是 SQL 合并?
    • @Ferdipux 处理合并
    • 感谢您在 MERGE 上发表您的意见 - 从提供的链接中获取一些有趣的观点。
    • @ChrisAlbert 我存储为二进制文件,但也明确地将 Historical/ChangeHashKey 转换为其 ASCII 表示,以允许 SSIS 条件拆分工作。所以我的源查询,对于 md5 散列有第二对列,如 CONVERT(varchar(34), D.ChangeHashKEY, 1) AS ChangeHashKeyASCII
    猜你喜欢
    • 2011-10-09
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多