EF SaveChangesAsync非常慢

时间:2016-01-22 13:57:52

标签: c# entity-framework

我有一张表,我希望一次更新100行。我有一个用于查找特定行的100个ID的列表。找到后,我会为每一行更新一个列(SyncOk)。

问题是更新100行需要 23到30秒

dbContext.Configuration.ValidateOnSaveEnabled = false;
var count = ids.Count;
for (var i = 0; i < count; i++)
{
    var id = ids[i];
    var record = await dbContext.History
        .FirstOrDefaultAsync(r => r.Id == id);
    record.SyncOk = syncOk;
}
await dbContext.SaveChangesAsync();

一些注意事项:

  • idsIList<long>,其中包含所有感兴趣的ID。
  • syncOk是一个布尔人。
  • 我尝试将AutoDetectChangesEnabled属性设置为false,然后在设置SyncOk值后手动更新记录 - 不会加快速度。

为什么SaveChangesAsync()这么慢 - 如何才能提高上述功能的速度?我害怕桌子在23-30秒内被锁定并会让其他服务(使用同一个表)也无法更新它。

3 个答案:

答案 0 :(得分:5)

您正在向数据库执行总共ids.Count个SELECT语句。如果添加代码,可以看到这一点:

dbContext.Database.Log += Console.WriteLine;

尝试通过一次获取所有数据来最小化对SQL实例的访问:

var records = await dbContext.History.Where(i => ids.Contains(i.Id)).ToListAsync();

然后你应该执行你需要的修改:

foreach(var record in records)
{
    record.SyncOk = syncOk;
}
await dbContext.SaveChangesAsync();

你也可以使用ForEachAsync来查询结果,就像上面的代码部分一样只查询一次:

await dbContext.History.Where(i => ids.Contains(i.Id))
                       .ForEachAsync(i => i.SyncOk = syncOk);
await dbContext.SaveChangesAsync();

答案 1 :(得分:1)

恕我直言Select * from History where Id in (YourList)在下面进行。

var listOfRecordsToBeUpdated = await dbContext.History
        .Where(r => ids.Contains(r.Id)).ToListAsync();

//It will detect the changes each time when you update the entity
// Make sure you re-enable this after your bulk operation
DataContext.Configuration.AutoDetectChangesEnabled = false;

//Iterate through the records and assign your value
listOfRecordsToBeUpdated.Foreach(x=>x.SyncOk = syncOk);

DataContext.Configuration.AutoDetectChangesEnabled = true;

await conn.SaveChangesAsync();

Increase performance by disabling AutoDetectChangesEnabled

答案 2 :(得分:1)

我尝试实施其他两个答案所建议的更改 - 但性能结果相同(即速度没有变化)。

我通过使用原始SQL命令大大提高了性能(并解决了我的问题):

var stringOfIds = string.Join(",", ids);
await dbContext.Database.ExecuteSqlCommandAsync(
    $"UPDATE dbo.History SET SyncOk = 1 WHERE Id IN ({stringOfIds})");