【问题标题】:SSIS ForEach ADO Enumerator - Performance IssuesSSIS ForEach ADO 枚举器 - 性能问题
【发布时间】:2019-01-08 00:29:56
【问题描述】:

这是关于使用 ADO Enumerator ForEach 循环的最佳实践/其他方法问题。

我的数据是财务账户,从源系统进入数据仓库。 数据的当前结构是金融交易列表,例如。

+-----------------------+----------+-----------+------------+------+
|      AccountGUID      | Increase | Decrease  |    Date    | Tags |
+-----------------------+----------+-----------+------------+------+
| 00000-0000-0000-00000 |        0 |    100.00 | 01-01-2018 | Val1 |
| 00000-0000-0000-00000 |   200.00 |         0 | 03-01-2018 | Val3 |
| 00000-0000-0000-00000 |   400.00 |         0 | 06-01-2018 | Val1 |
| 00000-0000-0000-00000 |        0 |    170.00 | 08-01-2018 | Val1 |
| 00000-0000-0000-00002 |   200.00 |         0 | 04-01-2018 | Val1 |
| 00000-0000-0000-00002 |        0 |    100.00 | 09-01-2018 | Val1 |
+-----------------------+----------+-----------+------------+------+

我的 SSIS 包,当前有两个 forEach 循环

  1. 所有时间余额
  2. 月末余额

所有时间余额

将 AccountGUID 传递到循环中并选择该帐户的所有交易。然后它按日期对它们进行排序,第一笔交易在前,并为其分配一个序列号。

一旦分配了序列号,它就开始根据增加和减少的cols计算当前的余额,连同标签col一起计算出它处理的余额。

它通过为最新记录分配当前标志来完成此操作。

所有时间平衡 - 工作流程

->Get All Account ID's in Staging table
|-> Write all Account GUID's to object variable
|--> ADO Enumerator ForEach - Loop Account GUID List - Write GUID to variable
|---> (Data Flow) Select all transactions for Account GUID
|----> (Data Flow) Order all transactions by date and assign Sequence number
|-----> (Data Flow) Run each row through a script component transformation to calculate running totals for each record
|------> (Data Flow) Insert balance data into staging table 

月末余额

第二个包 End of Month 做了非常相似的事情,除了第二个循环。选择将找到最早的跨国记录和最新的跨国记录。使用这两个日期,它将计算出这两个日期之间的所有月份,并为每个月份循环。

在日期循环内部,它做的事情几乎相同,根据标签计算余额,并在每个帐户的月末记录上加盖戳。

问题/问题

目前所有这些都运行良好,但性能很糟糕。

在一个包含大约 8000 个帐户和 500,000 笔交易的数据库中。此过程需要一天以上的时间才能运行。作为我们的小客户之一,我对为我们庞大的数据库运行它的想法感到颤抖。

有没有更好的方法来做到这一点,使用 SQL 游标或其他我没见过的巧妙方法?

【问题讨论】:

  • 我可能遗漏了一些东西。您是否有理由不使用带有 SUM 和 GROUP BY 的 SQL 进行插入?我不明白你为什么要使用这么多离散的步骤。
  • 嘿,Ben,所以它目前这样做的原因是为了时间点。所以占据了顶部的桌子。对于帐户 00000-0000-0000-00000,01-01 的余额为 -100,03-01 的余额为 +100,06-01 的余额为 +500。除了运行余额之外,您如何看待使用 SUM 和 Group by 在没有复杂 WHERE 子句的情况下保持该运行值?
  • 哦,好的。我读它的方式是你想要一个总金额和每月总金额,而不是增量。很公平。
  • 尝试使用执行 Sql 语句而不是在数据流中执行。在数据流中排序数据可能非常慢。
  • 你是说只在执行 sql 任务中进行排序和排序?我觉得循环的绝对数量对其产生了非常严重的影响 - 在调试中排序似乎没有产生巨大的影响?

标签: sql ssis etl business-intelligence


【解决方案1】:

好的,所以我已经设法将我的包执行时间从大约 3 天缩短到大约 11 分钟。

我在运行循环时运行了分析器和标准 Windows 统计信息,发现了一些有趣的事情。

首先,在执行包的过程中几乎没有使用 HDD、CPU、RAM 或网络。它告诉我我已经知道的事情,它没有尽可能快地运行。

我注意到的是,在循环的每次执行之间,在循环的下一个实例开始执行之前会有 1 到 2 毫秒的延迟。

最终我发现每次循环的新实例开始时,SSIS 都会创建一个到 SQL 数据库的新连接,看来这是 SSIS 的默认行为。每当您创建源或目标时,都会给您的项目添加连接延迟。

解决方法:

现在这是一个奇怪的修复,你需要进入你的连接管理器(奇怪的位)它必须是屏幕上的窗口而不是右侧的项目管理器窗口。

如果您选择循环中引用的连接,右侧的属性窗口(无论如何在我的布局中)您将看到名为“RetainSameConnection”的选项默认设置为 false。

通过将此设置为 true,我消除了 2ms 的延迟。

注意事项:

在此过程中,我创建了一堆其他问题,这些问题实际上只是突出了我的软件包中我没有好好考虑的区域。

似乎受此更改影响的一些事情是使用临时表的存储过程,这些似乎立即中断。我认为这是因为 SQL 处理临时表的方式,在关闭连接并重新打开时,您可以非常确定临时表已经消失。使用相同的连接设置,遇到临时表的机会似乎又是一个问题。

我删除了所有临时表并用 CTE 语句替换它们,这似乎解决了这个问题。

我发现的第二个主要问题是并行运行的任务并且都使用相同的连接管理器。由此我收到一条错误消息,表明 SQL 仍在尝试运行上一条语句。这炸毁了我的包裹。

为了解决这个问题,我创建了一个重复的连接管理器(我为同一个数据库创建了三个连接管理器)。

一旦我建立了连接,我就进入了我的每个并行源和目标,并为它们分配了自己的连接管理器。这似乎解决了我收到的最后一个错误。

结论:

这样做可能是更无法预料的问题,但现在我的包裹正在​​快速减轻,这突出了我设计中的一些缺陷。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    • 2018-10-28
    • 2013-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多