这是有关使用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循环
所有时间余额
将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
月末余额
第二个包,月末,除了第二个循环外,其他功能非常相似。选择的人员将找到最早的跨国记录和最新的跨国记录。使用这两个日期,它将计算出这两个日期之间的所有月份,并为每个月份循环。
在日期循环中,它执行几乎相同的操作,根据标签计算余额并标记每个帐户的月末记录。
问题/问题
目前所有这些方法都可以正常工作,但是性能太差了。
在一个大约有8000个帐户和500,000个事务的数据库中。该过程需要一天以上的时间才能运行。这是我们较小的客户之一,我不禁为大型数据库运行它。
是否有更好的方法,例如使用SQL游标或我未曾见过的其他巧妙方法来做到这一点?
答案 0 :(得分:0)
好的,所以我设法将包的执行时间从大约3天提高到大约11分钟。
我在运行循环时运行了探查器和标准的Windows统计信息,发现了一些有趣的东西。
首先,在执行软件包期间几乎没有使用HDD,CPU,RAM或网络。它告诉了我我所知道的,它没有尽可能快地运行。
我确实注意到,在每次循环执行之间,在下一个循环实例开始执行之前有1到2ms的延迟。
最终,我发现每次循环的新实例开始时,SSIS都会创建与SQL数据库的新连接,这似乎是SSIS的默认行为。每当您创建“源”或“目标”时,都会在项目中添加连接延迟。
修复:
现在这是一个奇怪的修复,您需要进入连接管理器(奇数位),它必须是屏幕上的窗口,而不是右侧的项目管理器窗口。
如果选择循环中引用的连接,则右侧的属性窗口(无论如何在我的布局中)中,您将看到名为“ RetainSameConnection”的选项,其默认设置为false。
通过将其设置为true,我消除了2ms的延迟。
注意事项:
为此,我创建了许多其他问题,这些问题实际上只是突出了我的包装中一些我没有深思熟虑的地方。
一些似乎受到此更改影响的事情是使用临时表的存储过程,这些似乎立即中断。我认为这是由于SQL处理临时表的方式所致,在关闭连接并重新打开时,您可以确定临时表已消失。使用相同的连接设置,再次进入临时表的机会似乎又是一个问题。
我删除了所有临时表并将其替换为CTE语句,这似乎可以解决此问题。
我发现的第二个主要问题是任务并行运行并且都使用相同的连接管理器。由此,我收到一个错误,指出SQL仍在尝试运行上一条语句。这炸毁了我的包裹。
要解决这个问题,我创建了一个重复的连接管理器(总共为同一个数据库制作了三个连接管理器)。
建立连接后,我进入了每个并行的源和目标,并为其分配了自己的连接管理器。这似乎已经解决了我收到的最后一个错误。
结论:
这样做可能是更不可预见的问题,但是目前我的程序包日新月异,这突出了我设计中的一些缺陷。