我每天都运行一个SSIS包来处理给定目录中的CSV文件。每个CSV文件包含~2000行,每行只有一列,其中包含10或11个字符的字符串。该包将数据插入记录集,循环遍历行,并为每行调用最多两个存储过程。
通常,每天只有一个CSV文件位于relavant目录中,因此将处理大约2000行。我又增加了10个,总计在20,000到25,000行之间。当程序包运行时,它在最后的~2000行中抛出了以下错误:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: ERROR - unable to allocate an environment handle.
at System.Data.Odbc.OdbcHandle..ctor(SQL_HANDLE handleType, OdbcHandle parentHandle)
at System.Data.Odbc.OdbcConnection.CreateStatementHandle()
at System.Data.Odbc.OdbcCommand.GetStatementHandle()
at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, String method, Boolean needReader, Object[] methodArguments, SQL_API odbcApiMethod)
at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, String method, Boolean needReader)
at System.Data.Odbc.OdbcCommand.ExecuteNonQuery()
at ST_5d19344133644426ade9d7b3f8a994c2.csproj.ScriptMain.Main()
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript()
一些快速的谷歌搜索表明这个错误与可用内存的问题有关,但我真的无法理解它。
所以,我有一些问题:
1)在尝试调用存储过程的上下文中,此错误的真正含义是什么?
2)我把包的数据流缓冲区DefaultBufferSize设置为默认设置(10 MB,如果我记得的话),但我还是明白SSIS会根据需要改变大小和最大行数吗?这有关系吗?
答案 0 :(得分:0)
我不确定错误的含义,但您是否有迹象表明可能存在内存压力? odbc驱动程序是32位还是64位?
至于如何在SSIS数据流中管理内存,SSIS将使用DefaultBufferMaxSize和DefaultBufferMaxRows作为为每个缓冲区分配多少行的边界。使用默认值,它将最多10 MB或10,000行,以较大者为准,不超过这些边界。 SSIS不会更改这些值,但您可以将内存大小增加到100 MB。
编辑: 该公式将起到这样的作用:
RowsPerBuffer = If (DefaultBufferMaxRows * RowSize) > DefaultBufferMaxSize
Then (DefaultBufferMaxSize / RowSize)
Else DefaultBufferMaxRows
鉴于您的上述陈述,您应该看到每个缓冲区接近10k行。 增加默认值会为数据流分配更多内存,因此如果服务器内存严重不足,可能会对ODBC连接造成压力。
每行调用一个或两个过程是一个密集的过程。您可以考虑将这些值导入到临时表中,并使用数据库引擎以基于集合的方式执行繁重的工作。
编辑: 为了阐明基于集合的方法,我来自SQL ETL开发背景,所以我通常会考虑如何快速处理大量数据。同样,我想到如何以最少的开发量完成这项工作,同时仍然满足完整的要求。所以基本的经验法则是:
因此,如果您为每一行调用proc,则意味着SQL中存在对此行集很重要的数据。您可以执行以下操作:
最终结果是,您将拥有性能更好,维护更好的软件包。