简体   繁体   English

EF SaveChangesAsync非常慢

[英]EF SaveChangesAsync extremely slow

I have a table in which I want to update 100 rows at a time. 我有一个表,我想一次更新100行。 I have a list of the 100 IDs that I use to find the specific rows. 我列出了用于查找特定行的100个ID。 Once found, I update a single column (SyncOk) for each row. 找到后,我为每一行更新一列(SyncOk)。

The problem is that updating 100 rows takes around 23 to 30 seconds . 问题是更新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();

Some notes: 一些注意事项:

  • ids is an IList<long> that holds all IDs of interest. ids是一个IList<long> ,其中包含所有感兴趣的ID。
  • syncOk is a bool. syncOk是一个布尔值。
  • I've tried to set the AutoDetectChangesEnabled property to false, and then updating the record manually just after setting the SyncOk value - doesn't speed things up. 我尝试将AutoDetectChangesEnabled属性设置为false,然后在设置SyncOk值后SyncOk手动更新记录-不会加快速度。

Why is SaveChangesAsync() so slow - how can I increase the speed of the above functionality? 为什么SaveChangesAsync()这么慢- 如何提高上述功能的速度? I'm afraid that the table is locked during the 23-30 seconds and will make other services (that use the same table) unable to update it as well. 恐怕该表在23到30秒内被锁定,并且会使其他服务(使用同一表)也无法更新它。

You are executing a total of ids.Count SELECT statements to the database. 您正在执行的ids.Count总数为数据库ids.Count SELECT语句。 This can be seen if you add the code: 如果添加代码,则可以看到:

dbContext.Database.Log += Console.WriteLine;

Try to minimize the access to the SQL-Instance by fetching all the data at once: 通过一次获取所有数据,尝试最小化对SQL实例的访问:

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

Then you should perform the modification you need: 然后,您应该执行所需的修改:

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

you could also use the ForEachAsync which will query the result like the above portion of code also only once: 您也可以使用ForEachAsync ,该查询将只查询一次上述代码部分的结果:

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

IMHO Select * from History where Id in (YourList) is performed below. 恕我直言, Select * from History where Id in (YourList)下面的Select * from History where Id in (YourList)中执行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 通过禁用AutoDetectChangesEnabled提高性能

I tried implementing the changes suggested by the two other answers - but with the same performance result (ie, no change in speed). 我尝试实现其他两个答案建议的更改-但是具有相同的性能结果(即,速度没有变化)。

I increased the performance greatly (and fixed my issue) by using a raw SQL command: 通过使用原始SQL命令,我极大地提高了性能(并解决了我的问题):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM