簡體   English   中英

為什么實體框架dbSet.Include需要這么長時間才能返回?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM