![](/img/trans.png)
[英]How should a C# windows app interact with a database when atomically dealing with large sets of data
[英]C# OutOfMemory Issue when dealing with large data
在我们的应用程序中,我们使用Windows Service生成报告。 使用存储过程从SQL Server中获取报表数据。 在某些情况下,返回的结果集包含250,000条记录(我们对此无济于事,我们需要一口气获得此数据,因为我们需要对此进行一些计算)。
问题
我们的应用程序正在读取器中获取此数据,并且正在自定义对象的自定义集合中转换此数据集。 由于数据量巨大,因此无法将完整的数据存储在自定义对象中,从而导致内存不足。 当我们在执行记录时看到任务管理器的进程使用情况时,它变得非常高,甚至CPU利用率也很高。
我不确定在这种情况下应该怎么做。
- 我们可以增加分配给在CLR下运行的单个进程的内存大小吗?
- 还有其他解决方法吗?
任何帮助将非常感激
- 为什么我一次需要所有数据:我们需要对完整的结果集进行计算
- 我们正在使用ADO.NET并将数据集转换为我们的自定义对象(集合)
- 我们的系统是32位
- 我们无法分页数据
- 无法将计算移至SQL Server
此堆栈跟踪可能有帮助:
引发了类型为'System.OutOfMemoryException'的异常。 服务器堆栈跟踪:位于System.Collections.Generic.Dictionary
2.ValueCollection.System.Collections.Generic.IEnumerable<TValue>.GetEnumerator() at System.Linq.Enumerable.WhereEnumerableIterator
1.MoveNext()位于System.Collections.Generic。清单1.InsertRange(Int32 index, IEnumerable
System.Collections.Generic上的1.AddRange(IEnumerable
1.InsertRange(Int32 index, IEnumerable
1集合)清单1.InsertRange(Int32 index, IEnumerable
C:\\ Ashish-Stuff \\中MyProject.Common.Data.DataProperty.GetPropertiesForType(Type t)的1.AddRange(IEnumerable
1集合) Projects \\ HCPA \\ Dev Branch \\ Common \\ Benefits.Common \\ Data \\ DataProperty.shared.cs:MyProject.Common.Data.Extensions.GetProperties中的第60行[T](T目标)在C:\\ Ashish-Stuff \\ Projects \\ HCPA \\ Dev Branch \\ Common \\ Benefits.Common \\ Data \\ Extensions.shared.cs:MyProject.Common.Data.Factories.SqlServerDataFactoryContract1.GetData(String procedureName, IDictionary
2参数,Nullable1 languageId, Nullable
1 pageNumber,第30行可为1页大小)
谢谢,Ashish
您能否每1000行数据将自定义的对象集合序列化到磁盘上的某个位置? 然后,当您返回数据时,是否从这些文件中分页?
有关您的用例的更多信息,为什么需要回退250万行数据将很有帮助。
我的第一个想法是,可以通过某些存储过程在Sql-Server端进行计算。 我怀疑这个方法需要一定的SQL服务器的绝地......但无论如何,你有没有考虑过这样的做法?
我希望看到一个代码示例,突出显示您从何处得到此错误。 是在数据提取本身上(填充读取器)还是在创建对象并将其添加到自定义集合中(填充集合)。
以前我曾遇到过类似的问题,涉及非常大的数据集,但在将其尽可能长时间地保留在流中方面取得了巨大的成功。 流将数据直接保存在内存中,直到您完成对象的构建,您才真正拥有对整个混乱的直接访问权限。 现在,由于堆栈跟踪显示“ MoveNext”操作上的错误,因此这可能对您不起作用。 然后我会说尝试对数据进行分块,一次抓取1万行或类似的东西,我知道这可以使用SQL来完成。 但是,这将使数据读取花费更长的时间。
编辑
如果您从数据库中将其读取到本地流中,然后又将其传递(只是注意不要将其关闭),那么就不应遇到这些问题。 制作一个数据包装器类,您可以使用开放流和开放阅读器来传递它。 将数据存储在流中,然后使用包装函数从中读取所需的特定数据。 诸如GetSumOfXField()
或AverageOfYValues()
等之类的东西……数据永远不会存在于活动对象中,但是您不必为此一直返回数据库。
伪示例
public void ReadingTheDataFunction()
{
DBDataReader reader = dbCommand.ExecuteReader();
MyDataStore.FillDataSource(reader)
}
private void FillDataSource(DbDataReader reader)
{
StreamWriter writer = new StreamWriter(GlobaldataStream);
while (reader.Read())
writer.WriteLine(BuildStringFromDataRow(reader));
reader.close();
}
private CustomObject GetNextRow()
{
String line = GlobalDataReader.ReadLine();
//Parse String to Custom Object
return ret;
}
从那里绕过MyDataStore,只要不关闭流和阅读器,就可以移动位置,查找单个条目,编译求和和平均值等。您甚至不必真正知道自己在哪里。只要您仅通过接口函数与活动对象交互,就不会处理该对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.