大数据表总是抛出System.outofmemory异常

时间:2015-08-25 18:19:48

标签: c# ado.net

我有一个包含大约500 000行的大型数据表。我必须遍历该数据表并在每一行上应用业务逻辑。 问题是,当经过一定程度的迭代后,它会抛出System.OutofMemory异常。

dt是包含500 000条记录的数据表。 我尝试了下面的方法:

int pageNum = 1;
int pageSize = 10000;
Datatable dtPage = null;
DataModel model = null;
//DataModel  is a class containing various properties 
//i.e public class DataModel
//{
//  public string Name {get;set;}
 // public string Role {get;set;}
//etc....
//}

while(dt.Rows.Count  - (pageNum * pageSize ) > 0)
{
 dtPage = dt.Rows.Cast<System.Data.DataRow>().Skip((pageNum -1 ) *   pageSize).CopyToTable();
foreach(DataRow row in dtPage.Rows)
{
model = new DataModel();
PropertyInfo[] properties = typeof(DataModel).GetProperties();
foreach(PropertyInfo property in properties)
{
if(dtPage.Columns.Contains(property.Name))
 SetNewValue(model,property.Name,row[property.Name]);
}
if(model! = null) lst.Add(model);
}
pageNum ++;
}

在这种情况下使用什么?我也试过了MoreLinq的批量方法,但仍然没有运气。

1 个答案:

答案 0 :(得分:0)

这行代码怎么样......

if(model! = null) lst.Add(model);

我怀疑这是你的罪魁祸首,因为你继续向一个超出你的循环范围的变量添加项目(这导致了问题,为什么还要麻烦所有复杂的分页逻辑呢?正在做的是将所有内容都转储到同一个列表中。)

您正在迭代具有五十万行的数据表,将其重新转换为每个页面的IEnumerable,使用反射迭代DataModel对象,使用反射设置属性,然后将新对象存储在集合中。在遍历表时,您的内存使用量确实会继续增长,因为您在每次迭代时都在创建新对象。

从性能和内存的角度来看,这种方法都是不切实际的。请考虑执行以下操作:

  • 将您的数据表仅转换为IEnumerable一次并将其存储在变量中,这样您就不会每次都重铸
  • 不要在像这样的巨大循环中使用反射。我不是反思,但表现会很糟糕。要么明确地编写代码来填充你的对象,要么考虑表达式树(虽然我相信这种情况下表达式树过于复杂)
  • 如果这是来自数据库,请在存储过程中实现分页,或者选择语句以仅提取单个页面所需的数据
  • 如果由于某种原因需要一次填充所有内容,则抛弃分页逻辑,因为您没有在上面的代码中使用它
  • 使用DataReader而不是DataTable。 DataReader比DataTable / DataSet
  • 更快,开销更少
  • 使用列索引而不是列名来检索数据。使用列名与索引会引入额外的性能损失。如果你需要动态地执行它,那么使用名称获取列的索引,存储它,并使用存储的值