OutOfMemoryException SqlCommand VarChar(Max)

时间:2011-04-14 18:04:34

标签: .net sql

我正在尝试使用ADO.NET(4.0 SP1)将大量字符串数据插入到SQLExpress R2的VARCHAR(MAX)字段中。该表有一列是VARCHAR(MAX)。目前,字符串的大小为77012287.以下是查询:

insert into dbo.t_test (c1) values (@c1);

我目前正在运行一个构建新字符串的测试应用程序,如下所示:

private static void ExecuteSqlQuery(int size) {
        Console.WriteLine("Inserting data. Parameter size: {0}", size);

        using (SqlConnection cn = new SqlConnection(SQL_CONNECTION_STRING)) {
            Console.WriteLine("Opening database connection.");
            cn.Open();

            using (SqlCommand cm = cn.CreateCommand()) {
                cm.CommandType = CommandType.Text;
                cm.CommandText = SQL_INSERT;
                cm.CommandTimeout = SQL_COMMAND_TIMEOUT;
                cm.Parameters.Add(SQL_PARM_DATA, SqlDbType.VarChar, -1).Value = new string('a', size);

                cm.ExecuteNonQuery();
            }

            Console.WriteLine("Closing database connection.");
        }
    }

尝试使用较大的值运行此方法时,我收到了SqlException。它实际上从未命中过数据库(我已经分析过SQL Express)。 SqlException是ExecuteNonQuery调用的TimeoutException。如果我在使用较大的数字运行它之前运行此方法几次,我将在ExecuteNonQuery调用上获得System.OutOfMemoryException。看起来内部解析器正在尝试使用char数组并抛出错误。如何将.NET中的大字符串值插入SQL Express?感谢。

2 个答案:

答案 0 :(得分:2)

有关如何将大文件流式传输到BLOB列的示例,请参阅Download and Upload images from SQL Server via ASP.Net MVC,查看BLOB数据的流式上传部分。您可以从codeproject下载代码。

它的要点是您需要以块的形式上传并使用UPDATE set column.WRITE语法,因为ADO.Net客户端没有正确的流语义。

另一种方法是使用FILESTREAM,因为SqlFileStream类型支持流式传输,有关完整示例,请参阅FILESTREAM MVC: Download and Upload images from SQL Server。但FILESTREAM存储带有它的怪癖,并不是一个微不足道的决定(特别是如果你的托管不提供它...)。

答案 1 :(得分:2)

听起来你的字符串最终会出现在Large Object Heap上并且没有被压缩。不幸的是,我不知道强制紧凑或清理大对象堆(LOH)的好方法,所以我能给出的最好建议是使用较短的字符串。


LOH的收入大于80Kb。请记住,因为字符串是不可变的,如果随着时间的推移构建字符串,您可能会在创建单个大字符串的过程中向LOH插入许多不同的字符串。这些其他字符串将由GC收集并且物理内存返回到操作系统,但由于LOH未被压缩(想要进行碎片整理),它们将继续占用您的进程可用的地址空间,这通常限制在仅2GB。此时,您将开始查看OutOfMemory异常。