SSIS包中的错误 - 无法分配环境句柄

时间:2015-01-28 12:00:37

标签: sql-server stored-procedures ssis sql-server-2008-r2 odbc

我每天都运行一个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会根据需要改变大小和最大行数吗?这有关系吗?

1 个答案:

答案 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开发背景,所以我通常会考虑如何快速处理大量数据。同样,我想到如何以最少的开发量完成这项工作,同时仍然满足完整的要求。所以基本的经验法则是:

  • 尽可能使用SSIS开箱即用的组件
  • 使包装成小的,可测试的单位
  • 尽可能避免逐行操作
  • 分阶段数据,以便利用数据库服务器完成更好的任务,例如合并数据集和排序数据

因此,如果您为每一行调用proc,则意味着SQL中存在对此行集很重要的数据。您可以执行以下操作:

  • 添加foreach循环以处理每个文件,并将数据流添加到此循环
  • 将自定义脚本源替换为标准平面文件源组件
  • 将数据按原样分阶段放入SQL表
  • 将proc逻辑替换为SQL查询,该查询将数据集连接在一起以获取所需的最终结果集。这个新任务可以进入它自己的存储过程。
  • 在foreach循环完成后在SSIS中的t-SQL任务中调用上述查询

最终结果是,您将拥有性能更好,维护更好的软件包。