以对数方式增加ForEach控件的每个循环的执行时间



首先,我是SSIS新手,刚刚完成了我的第二个数据导入项目。

该包非常简单,由一个数据流组成,该数据流将一个约30000条记录的以制表符分隔的客户值文件导入一个ADO记录集变量,该变量又用于为ForEach循环容器供电,该容器执行一段SQL,从记录集的每一行传入值。

第一个~21000条记录的导入花了59个小时才完成,但最终失败了!最后约9000人又花了8个小时。是的,总共67个小时!

SQL包括一个确定记录是否已经存在的检查,一个对过程的调用以生成新密码,以及一个对另一个过程的最终调用以将客户数据插入我们的系统。最后一个过程返回了一个记录集,但我对结果不感兴趣,所以我忽略了它。我不知道SSIS是否丢弃了该记录集。我知道这是将数据输入系统的最慢方法,但我没想到会这么慢,也没想到会在三分之二的过程中失败,在处理最后~9000个数据时再次失败。

当我在本地机器上测试大约3000个记录子集时,执行包实用程序报告每个插入大约需要1秒。经过一点快速的计算,建议整个导入大约需要8个小时才能运行。这似乎是一段很长的时间,考虑到我所读到的关于SSIS和RBAR执行的所有内容,这是我所期望的。我认为最终导入会更快一点,因为服务器的功能要强大得多。虽然我正在远程访问服务器,但我没想到这会成为一个问题,因为我过去曾使用定制的c#控制台应用程序进行导入,这些应用程序使用简单的ADO连接,运行速度几乎没有这么慢。

最初,目标表没有针对存在性检查进行优化,我认为这可能是性能缓慢的原因。我在表中添加了一个适当的索引,将测试从扫描更改为查找,希望这样可以解决性能问题。奇怪的是,它似乎没有明显的效果!

我们使用存储过程将数据插入系统的原因是为了保持一致性。如果数据通过我们的web前端插入到我们的系统中,它代表的路径与数据相同。数据的插入还导致许多触发器触发和更新数据库中的各种其他实体。

然而,在这次导入过程中发生的让我挠头的事情是,执行包实用程序的输出报告的SQL批处理的执行时间在运行过程中呈对数增长。一开始是不到1秒的执行时间,在导入过程中以超过20秒的时间结束,最终导入包只是完全停止。

感谢谷歌和StackOverflow,我已经在网上搜索了很多次,但没有找到任何描述这些症状的东西。

希望有人能找到线索。

感谢

回应ErikE:(我无法将其放入评论中,所以我在这里添加了它。)

埃里克。根据您的请求,我在数据库上运行了探查器,同时通过它的步伐运行了3000项测试文件。

我无法轻松地弄清楚如何让SSIS在代码中插入对探查器可见的可见差异,所以我只是在整个运行过程中运行探查器。我知道这会带来一些开销,但从理论上讲,它在运行过程中应该或多或少是一致的。

在整个运行过程中,每个项目的持续时间保持不变。

下面是轨迹的裁剪输出。在我在这里进行的运行中,前800个数据与之前输入的数据重叠,因此系统实际上没有做任何工作(Yay索引!)。一旦索引不再有用,系统实际上正在插入新数据,你就可以看到时间会相应地跳跃,但它们似乎没有太大变化,如果在第一个元素和最后一个元素之间有变化的话,读取次数是最大的项目。

------------------------------------------|项目|CPU|读取|写入|持续时间|------------------------------------------|0001|0|29|0|0||0002|0|32|0|0||0003|0|27|0|0||||0799|0|32|0|0||0800|78|4073|40|124||0801|32|2122|4|54||0802|46|2128|8|174||0803 | 46 | 2128 | 8 | 174||0804|47|2131|15|242||||1400 | 16 | 2156 | 1 | 54||1401|16|2167|3|72||1402|16|2153|4|84||||2997 | 31 | 2193 | 2 | 72||2998 | 31 | 2195 | 2 | 48||2999 | 31 | 2184 | 2 | 35||3000 | 31 | 2180 | 2 | 53|------------------------------------------

一夜之间,我还打开了探查器,对系统进行了全面的导入重新运行,以了解情况如何。在我的本地机器上,它在15.5小时内成功完成了进口量的三分之一。我将跟踪数据导出到SQL表中,以便从中获得一些统计信息。查看跟踪中的数据,插入之间的增量每处理1000条记录增加约1秒,因此当它达到记录10000时,每条记录需要10秒才能执行插入。为每条记录执行的实际代码如下。不要麻烦批评这个过程,SQL是由自学成才的开发人员编写的,早在任何受过开发人员教育的人被公司雇佣之前,他就已经是我们的接待员了。我们很清楚这不好。最重要的是,我认为它应该以恒定的速度执行,但显然不是。

if not exists
(
select 1
from [dbo].[tblSubscriber]
where strSubscriberEmail = @EmailAddress
and ProductId = @ProductId
and strTrialSource = @Source
)
begin
declare @ThePassword varchar(20)
select @ThePassword = [dbo].[DefaultPassword]()
exec [dbo].[MemberLookupTransitionCDS5] 
@ProductId
,@EmailAddress
,@ThePassword
,NULL --IP Address
,NULL --BrowserName
,NULL --BrowserVersion
,2 --blnUpdate
,@FirstName --strFirstName
,@Surname --strLastName
,@Source --strTrialSource
,@Comments --strTrialComments
,@Phone --strSubscriberPhone
,@TrialType --intTrialType
,NULL --Redundant MonitorGroupID
,NULL --strTrialFirstPage
,NULL --strTrialRefererUrl
,30 --intTrialSubscriptionDaysLength
,0 --SourceCategoryId
end
GO

确定每次执行之间的时间差的结果(为简洁起见,裁剪)。

----------------------|行|增量(毫秒)|----------------------|500 | 510||1000 | 976||1500 | 1436||2000 | 1916||2500 | 2336||3000 | 2816||3500 | 3263||4000 | 3726||4500 | 4163||5000 |4633||5500 | 5223||6000 | 5563||6500 | 6053||7000 | 6510||7500 | 6926||8000 | 7393||8500 | 7846||9000 | 8503||9500 | 8820||10000 | 9296||10500 | 9750|----------------------

让我们采取一些步骤:

  1. 建议:隔离是服务器问题还是客户端问题。运行跟踪,查看第一次插入与第3000次插入相比需要多长时间。在SQL语句中包括第一次和第3000次迭代的一些差异,这些差异可以在跟踪中进行筛选,这样就不会捕获其他事件。尽量避免语句完成--使用批处理或RPC完成。

    响应:探查器跟踪记录的CPU、读取和持续时间没有增加,但实际运行/有效插入时间为。

  2. 建议:假设上述模式在第10000次插入时都成立(如果不同,请提供建议),我的最佳猜测是发生了一些阻塞,可能是像约束验证一样,正在进行嵌套循环连接,这将与表中的行数成对数比例,正如您所看到的那样。你能做以下事情吗:

    • 使用SET SHOWPLAN_TEXT ON提供INSERT语句的完整执行计划
    • 对Blocked Process Report事件运行跟踪,并报告任何感兴趣的内容
    • 请阅读《消除大型事务中外键引起的死锁》,让我知道这是否是原因,或者我是不是找错了树

    如果这些都没有在问题上取得进展,只需在此处用任何新信息和评论更新您的问题,我将继续尽我所能提供帮助。

最新更新