EF SaveChangesAsync extremely slow

本文关键字:slow extremely SaveChangesAsync EF | 更新日期: 2023-09-27 18:31:37

>我有一个表,我想一次更新 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();

一些注意事项:

  • ids是保存所有相关 ID 的IList<long>
  • syncOk是一个布尔值。
  • 我尝试将 AutoDetectChangesEnabled 属性设置为 false,然后在设置 SyncOk 值后手动更新记录 - 不会加快速度。

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

EF SaveChangesAsync extremely slow

您正在对数据库执行总共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();

恕我直言,下面执行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();

通过禁用自动检测更改启用来提高性能

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

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

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