2016-01-22 44 views
1

我有一张表,我想每次更新100行。我有用于查找特定行的100个ID的列表。一旦找到,我为每一行更新一列(SyncOk)。EF SaveChangesAsync极慢

问题是,更新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是一个IList<long>保存所有感兴趣的标识。
  • syncOk是一个布尔。
  • 我试图将AutoDetectChangesEnabled属性设置为false,然后在设置SyncOk值后手动更新记录 - 不会加快速度。

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

+0

它不是。数据库模式有问题(缺少索引也许?)或许多其他客户端正在碰到同一个表(即使是1秒也是如此)。在talbe上是否定义了任何触发器?你计时'SaveChanges'自己或实际执行100选择的整个代码? –

+0

@PanagiotisKanavos:时间是执行上面的整个代码的持续时间。没有其他客户正在使用该表atm。让我回到你的索引。 – eightx2

+0

然后,您计算与单个“SELECT TOP 1”查询相对应的100个单独的FirstOrDefaultAsync语句,而不是** SaveChanges。这只是一个糟糕的SQL。您应该告诉EF加载其ID在列表中的所有历史记录项目,类似于“WHERE x IN(...)”语句。 –

回答

1

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

我用原始的SQL命令,大大提高了性能(和固定我的问题):

var stringOfIds = string.Join(",", ids); 
await dbContext.Database.ExecuteSqlCommandAsync(
    $"UPDATE dbo.History SET SyncOk = 1 WHERE Id IN ({stringOfIds})"); 
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

恕我直言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