[英]Why is Entity Framework dbSet.Include taking so long to return?
我在表上做一個簡單的“獲取”,例程的“包含”部分花費的時間比我期望的要長得多。
我將性能問題縮小到以下代碼段:
private List<Task> GetFilteredTasksWithOptionalIncludes(EntityRepository<Task> repo, ITaskRequest model, TaskIncludesModel includes, string accountID)
{
var includedEntities = new List<Expression<Func<Task, object>>>();
includedEntities.Add(t => t.Document.Transaction.Account);
includedEntities.Add(p => p.Signature);
if (includes != null)
{
if (includes.IncludeWorkflowActions)
{
includedEntities.Add(p => p.Actions);
}
if (includes.IncludeFileAttachments)
{
includedEntities.Add(p => p.Attachments);
}
}
IQueryable<Task> tasks = repo.GetAllIncluding(includedEntities.ToArray()); //RETURNS SLOW
return tasks.ToList(); //RETURNS FAST
}
我的所有代碼運行都非常快,直到達到repo.GetAllInclude方法,如下所示:
public IQueryable<TEntity> GetAllIncluding(params Expression<Func<TEntity, object>>[] includeProperties)
{
foreach (var includeProperty in includeProperties)
{
dbSet.Include(includeProperty).Load();
}
return dbSet;
}
當我逐步執行代碼時,GetAllIncluded()行最多需要6或7秒的時間才能返回,但task.ToList()返回的時間不到一秒鍾(這是實際的SQL查詢運行時,因此這讓我感到驚訝)。
當我注釋掉加載include的foreach循環時,整個調用在不到一秒的時間內返回。 是什么原因導致包含內容花費這么長時間? 還有更好的方法嗎?
如果有幫助,這里是調用周圍的SQL事件探查器。 紅線上方的所有內容均來自GetAllIncluded調用。 紅線下方的所有內容都是對數據的實際查詢。 有沒有更有效的方法可以做到這一點? 看起來很簡單的通話似乎不需要10秒。
當您在該循環中調用.Load()
時,實際上是在訪問數據庫並將數據放入上下文中。
因此,根據您要執行該循環的頻率,您會不斷地運行該查詢。
我建議刪除.Load()
但您仍然可以保留.Load()
函數。 通用存儲庫的基本“包含”功能如下所示:
public IQueryable<TEntity> Including(params Expression<Func<TEntity, object>>[] _includeProperties)
{
IQueryable<TEntity> query = context.Set<TEntity>();
return _includeProperties.Aggregate(query, (current, includeProperty) => current.Include(includeProperty));
}
一旦調用了此方法並掌握了IQueryable
,只需對其調用.ToList()
即可僅從SQL中提取一次。
閱讀http://msdn.microsoft.com/en-gb/data/jj592911.aspx,以了解Load方法的實際作用。
根據您的評論進行編輯:
您可以實現我發布的上述功能,並以與您現在正在使用的方式類似的方式使用它,然后在需要時可查詢的任務上隱式調用Load()
。
private List<Task> GetFilteredTasksWithOptionalIncludes(EntityRepository<Task> repo, ITaskRequest model, TaskIncludesModel includes, string accountID)
{
var includedEntities = new List<Expression<Func<Task, object>>>();
includedEntities.Add(t => t.Document.Transaction.Account);
includedEntities.Add(p => p.Signature);
if (includes != null)
{
if (includes.IncludeWorkflowActions)
{
includedEntities.Add(p => p.Actions);
}
if (includes.IncludeFileAttachments)
{
includedEntities.Add(p => p.Attachments);
}
}
IQueryable<Task> tasks = repo.Including(includedEntities.ToArray());
tasks.Load();
return tasks.ToList();
}
或者作為Thewads的后續步驟,只需編寫一個很好的舊sproc以一次將所有這些返回多個集合中即可,然后可以使用適當的索引優化數據庫架構,並使其盡快運行。
那可能不會流行,但是當您開始談論數據庫性能時,它是一種更快的方法(並且更容易使用,因為您擁有所有用於性能調整的sql工具)...例如,打開查詢執行計划。 您可能會發現發瘋了。
另一個問題是……您真的需要所有這些數據嗎,在加載所有數據之前是否沒有可以應用的過濾條件? (假設您解決了多次加載問題)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.