使用SSIS的最佳增量加载方法,记录超过2000万

时间:2016-05-12 21:01:07

标签: sql oracle ssis

需要什么:我需要从oracle逐步加载到SQL Server 2012的2500万条记录。它需要在软件包中具有UPDATE,DELETE,NEW RECORDS功能。 oracle数据源总是在变化。

我拥有的内容:我之前已多次完成此操作,但没有超过1000万条记录。首先,我设置了一个[执行SQL任务]来获取结果集[最大修改日期]。然后我有一个查询只从[ORACLE SOURCE]>中提取数据。 [最大修改日期]并对目标表进行查找。

我有[ORACLE Source]连接到[Lookup-Destination表],查找设置为NO CACHE模式,如果我使用部分或完全缓存模式,我会收到错误因为我认为[ORACLE Source]是永远在改变。然后[Lookup]连接到[Conditional Split],我将输入一个类似下面的表达式。

(REPLACENULL(ORACLE.ID,"") != REPLACENULL(Lookup.ID,"")) 
|| (REPLACENULL(ORACLE.CASE_NUMBER,"") 
!= REPLACENULL(ORACLE.CASE_NUMBER,""))

然后我会将[Conditional Split]输出的行输出到临时表中。然后我添加一个[执行SQL任务]并使用下面的查询对DESTINATION-TABLE执行UPDATE:

 UPDATE Destination
 SET SD.CASE_NUMBER =UP.CASE_NUMBER,
     SD.ID           =   UP.ID,
 From Destination SD
 JOIN  STAGING.TABLE UP
    ON UP.ID = SD.ID

问题:这变得非常慢并且需要很长时间才能继续运行。我怎样才能改善时间并让它发挥作用?我应该使用缓存转换吗?我应该使用合并声明吗?

当它是数据列时,如何在条件拆分中使用表达式REPLACENULL?我会使用类似的东西:

(REPLACENULL(ORACLE.LAST_MODIFIED_DATE,"01-01-1900 00:00:00.000") 
 != REPLACENULL(Lookup.LAST_MODIFIED_DATE," 01-01-1900 00:00:00.000")) 

下面的图片:

Date Flow

Control flow

4 个答案:

答案 0 :(得分:4)

对于较大的数据集通常更快的模式是将源数据加载到本地登台表中,然后使用如下的查询来识别新记录:

SELECT column1,column 2
FROM StagingTable SRC
WHERE NOT EXISTS (
    SELECT * FROM TargetTable TGT 
    WHERE TGT.MatchKey = SRC.MatchKey
)

然后您只需将该数据集提供给插入内容:

INSERT INTO TargetTable (column1,column 2)
SELECT column1,column 2
FROM StagingTable SRC
WHERE NOT EXISTS (
    SELECT * FROM TargetTable TGT 
    WHERE TGT.MatchKey = SRC.MatchKey
)

更新如下:

UPDATE TGT
SET 
column1 = SRC.column1,
column2 = SRC.column2,
DTUpdated=GETDATE()
FROM TargetTable TGT
WHERE EXISTS (
    SELECT * FROM TargetTable SRC
    WHERE TGT.MatchKey = SRC.MatchKey
)

请注意附加列DTUpdated。您应始终在表中使用“上次更新”列来帮助进行审核和调试。

这是一种INSERT / UPDATE方法。还有其他数据加载方法,例如窗口化(选择要完全删除和重新加载的数据的尾随窗口),但方法取决于系统的工作方式以及是否可以对数据做出假设(即源中的发布数据永远不会出现改变)

您可以将单独的INSERTUPDATE语句压缩成单个MERGE语句,虽然它变得非常庞大,但我遇到了性能问题,还有其他文档记录MERGE

的问题

答案 1 :(得分:1)

不幸的是,做你正在尝试做的事情并不是一个好方法。 SSIS有一些控制和记录的方法来执行此操作,但正如您发现,当您开始处理大量数据时,它们也无法正常工作。

在以前的工作中,我们有类似的事情需要我们做。我们需要将源系统的医疗索赔更新到另一个系统,类似于您的设置。很长一段时间,我们只是截断目的地的一切,每晚重建。我想我们每天都在做超过2500万行。如果您能够在相当长的时间内将所有行从Oracle传输到SQL,那么截断和重新加载可能是一种选择。

然而,随着我们的销量增长,我们最终不得不摆脱这种局面。我们试图按照你正在尝试的方式做一些事情,但从来没有得到任何我们满意的东西。我们最终得到了一种非传统的过程。首先,每个医疗索赔都有一个唯一的数字标识符。其次,每当在源系统中更新医疗索赔时,个别索赔上的增量ID也会增加。

我们流程的第一步是提出任何新的医疗索赔或已经更改的索赔。我们可以很容易地确定这一点,因为唯一的ID和"更改ID"列在源和目标中都被索引。这些记录将直接插入目标表。第二步是我们的"删除",我们使用记录上的逻辑标志处理。对于实际删除,其中记录存在于目标但不再存在于源中,我认为通过从源系统中选择DISTINCT声明号并将它们放在SQL端的临时表中实际上最快。然后,我们只是进行了LEFT JOIN更新,将缺少的声明设置为逻辑删除。我们做了类似于我们的更新:如果我们的原始Lookup带来了更新版本的声明,我们将逻辑删除旧版本。我们经常会清理逻辑删除并实际删除它们,但由于逻辑删除指标已编入索引,因此不需要太频繁地完成。即使逻辑删除的记录数量达到数千万,我们也从未见过很多性能损失。

随着我们的服务器负载和数据源卷的变化,这个过程总是在不断发展,我怀疑您的流程可能也是如此。因为每个系统和设置都不同,所以对我们有用的一些东西可能不适合你,反之亦然。我知道我们的数据中心相对较好而且我们使用了一些愚蠢的快速闪存,因此截断和重新加载对我们来说非常长时间。在传统存储上可能不是这样,在传统存储中,您的数据互连速度不是很快,或者您的服务器没有位于同一位置。

在设计流程时,请记住删除是您可以执行的更昂贵的操作之一,其次是更新和非批量插入。

答案 2 :(得分:1)

我假设您在oracle表中有一些像(pk)列这样的标识。

1从目标数据库(SQL Server one)获取最大身份(业务密钥)

2创建两个数据流

a)从oracle中仅提取数据> max identity并直接将它们放入目的地。(因为这些是新记录)。

b)获取所有记录<最大身份和更新日期>最后一次加载将它们放入临时(临时)表(因为这是更新的数据)

3使用临时表记录(在步骤b中创建)的记录更新目标表

答案 3 :(得分:1)

enter image description here enter image description here 使用SSIS的增量方法

  1. 从目标表中获取Max(ID)和Max(ModifiedDate)并将它们存储在变量中

  2. 使用EXECUTE SQL TASK创建临时登台表并将该临时登台表名称存储到变量中

  3. 执行数据流任务,并使用OLEDB源和OLEDB目标从源系统中提取数据并加载 数据放入临时表变量

  4. 执行两个执行SQL任务,一个用于插入过程,另一个用于更新

  5. 删除临时表

    插入到sales.salesorderdetails中 ( salesorderid, salesorderdetailid, 运营商跟踪号, 订购数量, 产品编号, 特殊优惠, 单价, unitpriceiscount, 线总数 rowguid, 修改日期 ) SELECT sd.salesorderid, sd.salesorderdetailid, sd.carriertrackingnumber, sd.orderqty, sd.productid sd.specialofferid, sd.unitprice, sd.unitpriceiscount, sd.linetotal, sd.rowguid, 修改日期 从## salesdetails为sd WITH(nolock) 左加入sales.salesorderdetails as sa with(nolock) ON sa.salesorderdetailid = sd.salesorderdetailid 不存在 ( 选择 * 从sales.salesorderdetails sa sa.salesorderdetailid = sd.salesorderdetailid) AND sa.salesorderdetailid>?

    更新sa SET SalesOrderID = sd.salesorderid, CarrierTrackingNumber = sd.carriertrackingnumber, OrderQty = sd.orderqty, ProductID = sd.productid, SpecialOfferID = sd.specialofferid, 单价=标准单价, UnitPriceDiscount = sd.unitpriceiscount, LineTotal = sd.linetotal, rowguid = sd.rowguid, ModifiedDate =标准修改日期 从sales.salesorderdetails sa 左联接## salesdetails sd ON sd.salesorderdetailid = sa.salesorderdetailid 在sa.modifieddate> sd.modifieddate AND sa.salesorderdetailid <?

整个过程需要2分钟才能完成

Incremental Process Screenshot