sql-server-2008 - 如何在SSIS包中优化Upsert(更新和插入)操作?

标签 sql-server-2008 ssis

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

这是我的程序:

  • 截断登台表(EXECUTE SQL TASK)
  • 从开发表中提取数据到暂存(Data Flow Task)
  • 运行数据流任务
  • OLE DB Source
  • Conditional Split Transformation(使用的条件:[!]ISNULL(is_new_flag))
  • 如果是新插入的话,如果已有更新

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

    我不确定要提供什么其他详细信息,但是我可以提供要求的任何内容。

    最佳答案

    使用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中向RowNumber列中插入了约140万行具有唯一值的行。表dbo.DestinationTabledbo.StagingTable最初是空的。表dbo.SourceTable中的所有行都将标志 IsActive 设置为false。

    用两个OLE DB连接管理器创建了一个SSIS包,每个连接器都连接到SourceDestination数据库。设计了控制流程,如下所示:
  • 首先Execute SQL Task对目标数据库执行语句 TRUNCATE TABLE dbo.StagingTable ,以截断登台表。
  • 下一节将说明如何配置Data Flow Task
  • 第二个Execute SQL Task执行以下给定的SQL语句,该语句使用dbo.DestinationTable中可用的数据来更新dbo.StagingTable中的数据,并假定在这两个表之间存在唯一的键。在这种情况下,唯一键是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 Source使用SQL命令dbo.SourceTable读取数据SELECT RowNumber,CreatedOn, ModifiedOn FROM Source.dbo.SourceTable WHERE IsActive = 1
  • Lookup transformation用于检查表dbo.DestinationTable中是否已存在RowNumber值
  • 如果记录不存在,则将其重定向到名为OLE DB Destination Insert into destination table ,这会将行插入到dbo.DestinationTable
  • 如果记录存在,它将被重定向到名为OLE DB Destination Insert into staging table ,它将行插入dbo.StagingTable中。登台表中的数据将在第二个“执行SQL任务”中使用以执行批处理更新。

  • 要为OLE DB源激活更多行,我运行以下查询以激活一些记录
    UPDATE  dbo.SourceTable 
    SET     IsActive = 1 
    WHERE   (RowNumber % 9 = 1) 
    OR      (RowNumber % 9 = 2)
    

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

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

    要为OLE DB源激活更多行,我运行以下查询以激活一些记录
    UPDATE  dbo.SourceTable 
    SET     IsActive = 1 
    WHERE   (RowNumber % 9 = 3) 
    OR      (RowNumber % 9 = 5) 
    OR      (RowNumber % 9 = 6) 
    OR      (RowNumber % 9 = 7)
    

    程序包的第二次执行如下所示。第一次执行期间先前插入的314,268 rows被重定向到登台表。 628,766 new rows直接插入到目标表中。在我的机器上执行该软件包大约需要12 seconds。目标表中的314,268 rows在第二个“执行SQL任务”中已使用登台表中的数据进行了更新。

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

    我希望这给您一个实现解决方案的想法。

    关于sql-server-2008 - 如何在SSIS包中优化Upsert(更新和插入)操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14819999/

    相关文章:

    c# - SSIS C# 脚本任务不读取变量或参数

    sql-server - 提高大型数据集的 SSIS 包插入/删除速度(或者这样可以吗?)

    ssis - 创建重复包的最佳方法是什么?

    sql - SSRS - 将静态 null 添加到参数查询

    sql - SSIS DataFlowTask DefaultBufferSize 和 DefaultBufferMaxRows

    sql - 在一列中显示所有表 SQL 的所有文本字段

    error-handling - 在 SSIS 脚本中可能有多个 try/catch block 吗?

    sql - 识别整个数据库中复合 PK 中包含的所有列

    sql-server - 在 Visual Studio 中从 SQL Server Express 数据库获取数据库名称

    sql - 哪个 SSIS 可执行文件是用于删除命令的最佳实践