当处理400万条记录时,内存不足

3
我有以下代码,尝试处理400万条数据库记录:
private void intenseProcess4()
{
    using (connection1 = new SqlConnection("connection string goes here"))
    {
        using (command1 = new SqlCommand(@"stored procedure name goes here", connection1))
        {
            command1.CommandType = CommandType.StoredProcedure;

            try
            {
                connection1.Open();

                using (reader1 = command1.ExecuteReader())
                {
                    while (reader1.Read())
                    {
                        int PrjNameIndex1 = reader1.GetOrdinal("full_path");
                        Directory.CreateDirectory(Path.Combine(reader1.GetString(PrjNameIndex1)));
                    }

                    if (reader1.NextResult())
                    {
                        while (reader1.Read())
                        {
                            System.IO.File.Copy(reader1.GetString(SourceIndex), reader1.GetString(DestinationIndex), true);
                        }
                    }
                }
            }
            catch (SqlException ex)
            {
                File.AppendAllText(Path.Combine(@"h:\X\log\error.log"), ex + " SqlException caught." + Environment.NewLine);
            }
        }
    }
}

一旦启动,它可以正常运行约一个小时,但之后会出现以下错误信息:

Problem signature:
    Problem Event Name: CLR20r3
    Problem Signature 01:   devenv.exe
    Problem Signature 02:   12.0.21005.1
    Problem Signature 03:   524fcb34
    Problem Signature 04:   mscorlib
    Problem Signature 05:   4.0.30319.34209
    Problem Signature 06:   534894cc
Problem Signature 07:   226e
Problem Signature 08:   6
Problem Signature 09:   System.OutOfMemoryException
OS Version: 6.1.7601.2.1.0.256.49
Locale ID:  2057
Additional Information 1:   0a9e
Additional Information 2:   0a9e372d3b4ad19135b953a78882e789
Additional Information 3:   0a9e
Additional Information 4:   0a9e372d3b4ad19135b953a78882e789

在那段时间里,它只能通过大约35,000条记录。

请注意,行String DestinationString =String SourceString =是无用的。但这不应该是问题所在。 - xanatos
1
看起来你正在 VS 内部运行此程序。请确保你使用的是 Release 版本,并最好在 VS 外部运行。 - H H
我完全同意Holterman的分析。如果它仍然无法工作(但这非常奇怪,因为您没有分配太多的GC内存),您可以尝试在每1000个文件中执行一次GC.Collect()。在 while 之前:int num = 0;while 内部:if (++num % 1000 == 0) { GC.Collect(); } - xanatos
@HenkHolterman:这些文件只是被复制,而不是读入托管内存中。 - Guffa
@HenkHolterman,总共文件大小约为1TB。每个文件的大小不同。它们似乎平均约为0.25MB。 - oshirowanen
显示剩余4条评论
2个回答

1

尝试使用 CommandBehavior.SequentialAccess

当您指定SequentialAccess时,需要按返回的顺序从列中读取数据,尽管不需要读取每个列。一旦您已经读取超过返回的数据流中的位置,那么该位置或之前的数据将无法从DataReader中读取。

但是,尝试在一次操作中处理400万条记录的智慧是值得质疑的。我相信你永远不会成功地复制4百万个文件并保持结果集开放。你注定要一遍又一遍地重试。相反,考虑使用批处理,检索一小组文件进行处理,复制,记录进度,然后获取另一批。如果发生崩溃,请从上次进度恢复。

您还应考虑并行执行多个副本(使用异步IO,而不是线程!)。


1
我对最后一点不太确定,File.Copy 可以轻松饱和单个驱动器。 - H H
再想一想,第一个也不太确定。文件内容不在数据库中,只有文件名。 - H H
读取器流式传输数据。每次使用的内存不应超过1行。我不明白为什么任意多条记录本身会成为问题。 - usr

0
使用终端命令而非图形界面创建归档文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接