3

我有一个包含超过一百万条记录的表。每条记录包含大约 60 个字段,但我们只更改其中的三个。

我们根据计算和查找对每个实体进行小修改。

显然,我不能依次更新每个实体,SaveChanges因为那样会花费太长时间。

因此,在整个过程结束时,我调用SaveChangesContext.

当我申请时,这会导致内存不足错误SaveChanges

我正在使用 DataRepository 模式。

//Update code
DataRepository<ExportOrderSKUData> repoExportOrders = new DataRepository<ExportOrderSKUData>();
foreach (ExportOrderSKUData grpDCItem in repoExportOrders.all())
{
  ..make changes to enity..
}
repoExportOrders.SaveChanges();



//Data repository snip
public DataRepository()
{
  _context = new tomEntities();
  _objectSet = _context.CreateObjectSet<T>();
}
public List<T> All()
{
  return _objectSet.ToList<T>();
}
public void SaveChanges()
{
  _context.SaveChanges();
}

在这种情况下我应该寻找什么?

4

1 回答 1

4

在一个事务中通过 EF 更改 50 万条记录不是假设用例。小批量做是更好的技术方案。通过一些存储过程在数据库端执行它可能是更好的解决方案。

我将首先稍微修改您的代码(自己将其转换为您的存储库 API):

using (var readContext = new YourContext()) {
    var set = readContext.CreateObjectSet<ExportOrderSKUData>();

    foreach (var item in set.ToList()) {
       readContext.Detach(item);
       using (var updateContext = new YourContext()) {
          updateContext.Attach(item);
          // make your changes
          updateContext.SaveChanges();
       }
    }
}

此代码使用单独的上下文来保存项目 = 每个保存都在其自己的事务中。不要害怕那个。即使您尝试在一次SaveChangesEF 调用中保存更多记录,也会为每个更新的记录使用单独的数据库往返。唯一的区别是,如果您想在同一个事务中进行多次更新(但在单个事务中进行 50 万次更新无论如何都会导致问题)。

另一种选择可能是:

using (var readContext = new YourContext()) {
    var set = readContext.CreateObjectSet<ExportOrderSKUData>();
    set.MergeOption = MergeOption.NoTracking;

    foreach (var item in set) {
       using (var updateContext = new YourContext()) {
          updateContext.Attach(item);
          // make your changes
          updateContext.SaveChanges();
       }
    }
}

这在理论上可以消耗更少的内存,因为您不需要在执行之前加载所有实体foreach。第一个示例可能需要在枚举之前加载所有实体(通过调用ToList)以避免调用时出现异常Detach(在枚举期间修改集合) - 但我不确定这是否真的发生。

修改这些示例以使用一些批次应该很容易。

于 2013-04-11T07:39:28.483 回答