【问题标题】:SSIS is hanging during Update with 3 millions of rowsSSIS 在更新期间挂起,有 300 万行
【发布时间】:2019-05-05 04:54:23
【问题描述】:

我正在为仓库实施一种新方法。新方法包括在源表和目标表之间执行增量加载(插入、更新或删除)。

所有表都运行良好,除了 1 个表,其 Source 的行数超过 300 万行,如下图所示,它刚刚开始运行,但从未完成。 可能我没有以正确的方式进行更新,或者有其他方法可以做到这一点。

以下是我的 SSIS 包的一些图片:

突出显示的对象是它挂起的地方。 这是我调用来更新表的存储过程:

ALTER PROCEDURE [dbo].[UpdateDim_A] 
      @ID INT,
      @FileDataID INT
     ,@CategoryID SMALLINT
     ,@FirstName VARCHAR(50)
     ,@LastName VARCHAR(50)
     ,@Company VARCHAR(100)
     ,@Email VARCHAR(250) AS BEGIN
SET NOCOUNT ON;


BEGIN TRAN 
 UPDATE DIM_A 
    SET                  
        [FileDataID] = @FileDataID,
        [CategoryID] = @CategoryID,
        [FirstName]  = @FirstName,
        [LastName]   = @LastName,
        [Company]    = @Company,
        [Email]      = @Email

    WHERE PartyID=@ID

    COMMIT TRAN;  END

注意: 我已经尝试过删除约束和索引并将数据库的恢复模式更改为简单。

任何帮助将不胜感激。


应用@Prabhat G 提供的解决方案后,这是我的包的样子,运行时间为 39 秒(平均)!!!

在 Dim_A 数据流内部

【问题讨论】:

  • 这实际上是你正在做的最慢的方法。排序...单行更新。每次我打开别人的包裹看到这个我都会呻吟。将数据加载到临时表中并进行一次更新。不要按照你的方式去做。

标签: sql sql-server tsql stored-procedures ssis


【解决方案1】:

遵循这 2 个性能增强器,您将避免瓶颈。

  1. 删除sort 转换。在您的源代码中,在获取数据时使用order by sql。 原因是,sort 在排序之前占用了内存中的所有记录。你不希望这样,无论是增量负载还是全负载。

  2. 在更新的最后一步,引入另一个 Staging Table 而不是 update records oledb command,它将是 Dim 表的副本。一旦所有匹配的记录都插入到这个新的临时表中,退出数据流任务并创建EXECUTE SQL TASK,它将根据连接 ID/条件简单地更新 Dim 表。

原因是,oledb 命令逐行命中。始终喜欢使用Execute SQL Task 作为批处理更新。


编辑: 根据 cmets,要仅更新 Execute SQL Task 中更改的行,请在 where 子句中添加条件:

eg:

UPDATE x
SET
   x.attribute_A = y.attribute_A
  ,x.attribute_B = y.attribute_B
FROM
DimA x
 inner join stg_DimA y
ON x.Id = y.Id
WHERE
(x.Attribute_A <> y.Attribute_A
OR x.Attribute_B <> y.Attribute_B)

【讨论】:

  • 这是我见过的最好的解决方法。奇迹般有效。谢谢!!
  • 我会发布它现在的样子。
  • @JCACERES 为了提高性能,您应该考虑只将需要更新的记录放入暂存表中(有关详细信息,请参阅我的答案)。它不仅通过减少事务的大小来加快处理速度,而且应该减少更新和整个事务日志引起的索引碎片。
  • @JCACERES :很高兴提供帮助 :-) 检查我更新的答案。它涵盖了 J Weezy 的方法
  • 我会试试的,谢谢。
【解决方案2】:

所以您的问题实际上非常简单,您使用的方法是为返回的每一行执行该存储过程。如果您有 9961 行(如图所示)要更新,它将在 9961 单独的时间运行该语句。如果您要查看 SQL Server 上运行的活动查​​询,您可能会看到该过程一遍又一遍地执行。

您应该做的就是将数据转储到临时表中,然后在您的包中进一步使用执行 SQL 任务来运行标准 SQL 更新。这将运行得更快。

【讨论】:

  • 如果我这样做,我将丢失查找对象,该对象是比较源和目标的对象。
  • 我不确定我是否遵循。我在这里建议的是,而不是运行该更新。您在该数据流的位置获取所有这些值并将其插入到您正在暂存的表中。您可以保留数据流中的任何值。然后,一旦上演,您就可以运行更新。它的运行速度比您当前使用的方法快得多。
【解决方案3】:

问题是您正试图在数据流中执行存储过程。正确的 SqlCommand 将是一个显式的 UPDATE 查询,然后将 SSIS 中的列映射到您正在更新的表上的列。

UPDATE DIM_A 
SET FileDataID = ?
    ,CategoryID = ?
    ,FirstName = ?
    ,LastName = ?
    ,Company = ?
    ,Email = ?
WHERE PartyID = ?

注意:@Id 需要作为列包含在数据流中。

正如 Zane 正确指出的那样,您应该考虑的最后一件事是:您应该只更新已更改的行。因此,在您的数据流中,您应该添加一个条件拆分转换,以检查新源行中的任何列是否与现有表行不同。只有不同的行应该发送到 OLE DB 命令 - 其余的可以忽略。

【讨论】:

  • 是的,我已经这样做了,我会上传映射的图像。
  • 您不能在 OLE DB 命令中调用存储过程来更新表。您需要移动存储过程中包含的更新脚本并将其放在 SqlCommand 中。
  • 如果使用这种方法,它仍然很可能运行很慢,因为它将是逐行更新。
  • @Zane 毫无疑问,OLE DB 命令很慢。 JCACERES 应该有一个拆分转换,以仅从源发送与现有行不同的那些行。无需更新未更改的现有行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-15
  • 2011-03-22
  • 2010-11-15
  • 1970-01-01
相关资源
最近更新 更多