8

我不是 DBA,但我确实在一家小公司担任 IT 人员。我必须将数据库从登台复制到生产。我已经创建了一个 SSIS 包来执行此操作,但它需要几个小时才能运行。这也不是一个大型数据仓库类型的项目,它是一个非常简单的Upsert. 我假设我是我设计它的薄弱环节。

这是我的程序:

  1. 截断临时表 ( EXECUTE SQL TASK)
  2. 将开发表中的数据拉入暂存 ( Data Flow Task)
  3. 运行数据流任务
    1. OLE DB Source
    2. Conditional Split Transformation(使用条件[!]ISNULL(is_new_flag):)
    3. 如果新插入,如果现有更新

数据流任务被模仿了几次以更改表/值,但流程是相同的。我已经阅读了几篇关于 OLE DB 组件缓慢更新缓慢的内容,并尝试了一些事情但没有让它运行得非常快。

我不确定要提供哪些其他细节,但我可以提供任何要求的信息。

4

2 回答 2

11

使用批量操作插入或更新的 SSIS 2008 R2 示例包:

这是一个示例包SSIS 2008 R2,说明了如何使用批处理操作在两个数据库之间执行插入、更新。

  • 使用OLE DB Command会减慢包的更新操作,因为它不执行批处理操作。每行都单独更新。

该示例使用两个数据库,即SourceDestination。在我的示例中,两个数据库都驻留在服务器上,但逻辑仍然可以应用于驻留在不同服务器和位置的数据库。

dbo.SourceTable我在我的源数据库中创建了一个名为的表Source

CREATE TABLE [dbo].[SourceTable](
    [RowNumber] [bigint] NOT NULL,
    [CreatedOn] [datetime] NOT NULL,
    [ModifiedOn] [datetime] NOT NULL,
    [IsActive] [bit] NULL
)

此外,在我的目标数据库中创建了两个名为dbo.DestinationTable和的表。dbo.StagingTableDestination

CREATE TABLE [dbo].[DestinationTable](
    [RowNumber] [bigint] NOT NULL,
    [CreatedOn] [datetime] NOT NULL,
    [ModifiedOn] [datetime] NOT NULL
) 
GO

CREATE TABLE [dbo].[StagingTable](
    [RowNumber] [bigint] NOT NULL,
    [CreatedOn] [datetime] NOT NULL,
    [ModifiedOn] [datetime] NOT NULL
) 
GO

dbo.SourceTable将表中具有唯一值的大约 140 万行插入到RowNumber列中。桌子dbo.DestinationTabledbo.StagingTable开始都是空的。表中的所有行都dbo.SourceTable将标志IsActive设置为 false。

行数 - 1

创建了一个带有两个 OLE DB 连接管理器的 SSIS 包,每个连接管理器都连接到Source数据库Destination。设计控制流程如下图:

  • 首先对目标数据库Execute SQL Task执行语句TRUNCATE TABLE dbo.StagingTable以截断登台表。

  • 下一节将解释如何Data Flow Task配置。

  • SecondExecute SQL Task执行下面给定的 SQL 语句,该语句dbo.DestinationTable使用 中可用的数据更新数据dbo.StagingTable,假设这两个表之间存在匹配的唯一键。在这种情况下,唯一键是 column RowNumber

更新脚本:

UPDATE      D 
SET         D.CreatedOn = S.CreatedOn
        ,   D.ModifiedOn = S.ModifiedOn 
FROM        dbo.DestinationTable D 
INNER JOIN  dbo.StagingTable S 
ON          D.RowNumber = S.RowNumber

控制流

我设计了如下所示的数据流任务。

  • OLE DB Sourcedbo.SourceTable使用 SQL 命令读取数据SELECT RowNumber,CreatedOn, ModifiedOn FROM Source.dbo.SourceTable WHERE IsActive = 1

  • Lookup transformation用于检查表中是否已经存在 RowNumber 值dbo.DestinationTable

  • 如果记录存在,它将被重定向到OLE DB Destination命名为 as Insert into destination table,它将行插入到dbo.DestinationTable

  • 如果记录存在,它将被重定向到OLE DB Destination命名为Insert into staging table,它将行插入到dbo.StagingTable. 暂存表中的这些数据将用于第二个`Execute SQL Task 执行批量更新。

数据流选项卡

为了激活 OLE DB Source 的更多行,我运行了以下查询来激活一些记录

UPDATE  dbo.SourceTable 
SET     IsActive = 1 
WHERE   (RowNumber % 9 = 1) 
OR      (RowNumber % 9 = 2)

更新行 - 1

包的第一次执行如下所示。所有行都被定向到目标表,因为它是空的。在我的机器上执行包大约需要3 seconds.

执行 1

执行时间1

再次运行行计数查询以查找所有三个表中的行计数。

行数 - 2

为了激活 OLE DB Source 的更多行,我运行了以下查询来激活一些记录

UPDATE  dbo.SourceTable 
SET     IsActive = 1 
WHERE   (RowNumber % 9 = 3) 
OR      (RowNumber % 9 = 5) 
OR      (RowNumber % 9 = 6) 
OR      (RowNumber % 9 = 7)

行数 - 3

包的第二次执行如下所示。314,268 rows之前在第一次执行期间插入的内容被重定向到临时表。628,766 new rows直接插入到目标表中。在我的机器上执行包大约需要12 seconds. 314,268 rows在第二个执行 SQL 任务中使用临时表更新了目标表中的数据。

执行 - 2

执行时间 - 2

再次运行行计数查询以查找所有三个表中的行计数。

行数 - 3

我希望这能给你一个想法来实施你的解决方案。

于 2013-02-11T21:47:25.390 回答
8

我要看的两件事是您的插入(确保您使用“表或视图 - 快速加载”或“表名称或视图名称变量 - 快速加载”)和您的更新。

正如您已经正确确定的那样,更新逻辑通常是性能下降的地方,这是由于 OLE DB 组件为流经它的每一行触发单例更新。人们用来克服这个问题的常用方法是将所有更新写入临时表,就像您的插入逻辑一样。然后跟进您Data Flow TaskExecute SQL Task执行批量更新。

如果您打算购买 3rd 方工具,PragmaticWorks 提供了Upsert 目的地

于 2013-02-11T20:24:49.673 回答