为什么不两者兼而有之?
一般来说,我们在进行增量加载时会寻找两件事:这是否存在?如果存在,是否已更改。如果只有一列,那是微不足道的。当有很多列要检查时,这会变得相当痛苦,尤其是如果您使用 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,为什么我要使用专用的INSERT 和UPDATE 语句?除了不那么容易记住语法之外,SQL Server 实现还可以有一些...unintended consequences。它们可能是角落ish 案例,但我宁愿不要在我提供的解决方案中遇到它们。显式 INSERT 和 UPDATE 语句为我提供了我在解决方案中想要和需要的细粒度控制。我喜欢 SQL Server,认为它是一个很棒的产品,但它们奇怪的语法加上已知的错误使我无法在任何地方使用 MERGE,除非是认证考试。