我正在使用SSIS将数据从DB2数据库中的表迁移到我们的SQL Server数据库。我从中提取数据的表包含了相当数量的数据 - 少于100,000条记录;但是,它也有46列。
我只想更新需要更新的行,因此我得出结论,我可以使用查找转换并检查所有46列并重定向“无匹配”以在SQL表上更新。或者,在我在数据任务流开始时读取数据后,我可以对数据集中的每一行进行散列,然后,在确定行是否相等时,稍后使用散列值作为比较。 / p>
我的问题是:哪条路线更好?我喜欢哈希,但我不确定这是否是最好的选择。有没有人有他们想分享的任何智慧珍珠?
答案 0 :(得分:5)
为什么不两者?
一般来说,在进行增量加载时我们会寻找两件事:这是否存在?如果它存在,它是否已更改。如果只有一列,那就很简单了。当要检查的列很多时,这就变得非常痛苦,尤其是当您使用SSIS映射所有这些列和/或必须处理担心NULL时。
我通过作弊来解决多列问题 - 我在所有表中创建了两列:HistoricalHashKey和ChangeHashKey。历史哈希键将是所有业务键。更改哈希键是所有其他材料列(我将排除审计列之类的内容)。我们不会直接在哈希列中存储连接值。相反,“我们将数学中的东西用于它”并应用称为SHA-1的散列算法。该算法将获取所有输入列并返回20字节输出。
使用这种方法有三个注意事项。您必须每次以相同的顺序连接列。这些将区分大小写。尾随空间非常重要。就是这样。
在表中,您可以将两列添加为二进制(20)NOT NULL。
您的控制流程看起来像这样
并且您的数据流如此
(假设我来自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;
此查询将从我们的参考表中撤回存储的HistoricalHashKey和ChangeHashKey。
SELECT
DP.HistoricalHashKey
, DP.ChangeHashKey
FROM
dbo.DimProduct AS DP;
此时,比较HistoricalHashKeys以确定行是否存在是一件简单的事情。如果我们匹配,我们希望将ChangeHashKey拉回到我们的数据流中。按照惯例,我将此lkp_ChangeHashKey命名为与源ChangeHashKey区分开来。
条件分割也被简化了。两个Change Hash键匹配(无更改)或不更改(已更改)。那个表达式是
ChangeHashKey == lkp_ChangeHashKey
不是使用OLE DB命令,而是创建一个专用表来保存需要更新的行。 OLE DB命令在发布单例更新命令的幕后不能很好地扩展。
数据流完成后,需要更新的所有数据都将在我们的临时表中。此执行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;
为什么我使用专用的INSERT
和UPDATE
语句,因为我们有闪亮的MERGE
?除了不容易记住语法之外,SQL Server实现可以有一些...... unintended consequences。它们可能是角落 ish 的情况,但我宁愿不用我提供的解决方案遇到它们。明确的INSERT和UPDATE语句为我提供了我想要并在我的解决方案中需要的精细控制。我喜欢SQL Server,认为它是一个很棒的产品,但是他们奇怪的语法加上已知的错误使我无法在任何地方使用MERGE,只有认证考试。