2016-01-22 41 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