2012-10-07 96 views
1

我一直在試圖弄清楚如何優化以下查詢過去幾天,只是沒有多少運氣。現在我的測試數據庫返回的記錄數據非常少,只有很少的300條記錄,但運行時間需要4-5秒,LINQ生成的SQL非常長(這裏包含的時間太長)。任何建議將非常感激。實體框架超時

總結這個查詢,我試圖返回一個客戶端列表有點扁平的「快照」與當前狀態。一方包含一個或多個具有角色(ASPNET角色提供者)的客戶端,日誌將返回一個方中所有客戶端的最後1條日誌條目,同樣適用於Task和LastLoginDate,因此是OrderBy和FirstOrDefault功能。

Guid userID = 'some user ID' 
var parties = Parties.Where(p => p.BrokerID == userID).Select(p => new 
{ 
ID = p.ID, 
Title = p.Title, 
Goal = p.Goal, 
Groups = p.Groups, 
IsBuyer = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")), 
IsSeller = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "seller")), 
Journal = p.Clients.SelectMany(c => c.Journals).OrderByDescending(j => j.OccuredOn).Select(j=> new 
    { 
     ID = j.ID, 
     Title = j.Title, 
     OccurredOn = j.OccuredOn, 
     SubCatTitle = j.JournalSubcategory.Title 
    }).FirstOrDefault(), 
LastLoginDate = p.Clients.OrderByDescending(c=>c.LastLoginDate).Select(c=>c.LastLoginDate).FirstOrDefault(), 
MarketingPlanCount = p.Clients.SelectMany(c => c.MarketingPlans).Count(), 
Task = p.Tasks.Where(t=>t.DueDate != null && t.DueDate > DateTime.Now).OrderBy(t=>t.DueDate).Select(t=> new 
    { 
     ID = t.TaskID, 
     DueDate = t.DueDate, 
     Title = t.Title 
    }).FirstOrDefault(), 
Clients = p.Clients.Select(c => new 
    { 
     ID = c.ID, 
     FirstName = c.FirstName, 
     MiddleName = c.MiddleName, 
     LastName = c.LastName, 
     Email = c.Email, 
     LastLogin = c.LastLoginDate 
    }) 
}).OrderBy(p => p.Title).ToList() 

回答

0

我想張貼SQL可以給我們一些線索,像的排序依據之前或在投射後未來可能有很大的不同量級的小東西。

但無論如何,嘗試在一個單獨的查詢中提取客戶端,這可能會簡化您的查詢。然後包括其他表像雜誌和任務投射前,看看這會影響您的查詢:

 
    //am not sure what the exact query would be, and project it using ToList() 
    var clients = GetClientsForParty(); 

    var parties = Parties.Include("Journal").Include("Tasks") 
      .Where(p=>p.BrokerID == userID).Select(p => { 

    .... 
    //then use the in-memory clients 
    IsBuyer = clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")), 
    ... 
    } 
    ) 

在所有情況下,安裝EF profiler和看看你的查詢是如何受到影響。英孚可以安靜地令人驚訝。就像在投影之前放置OrderBy,所有這些FirstOrDefault或SingleOrDefault一樣,它們都可以產生很大的影響。

回到基礎,如果您在LoweredRoleName上搜索,那麼確保它被索引以便查詢速度很快(儘管這可能是無用的,因爲EF可能最終不會使用覆蓋索引它正在查詢很多其他列)。此外,由於這是查詢是查看數據(你不會改變數據),所以不要忘記關閉實體跟蹤,這也會給你一些性能提升。

最後,不要忘記,你總是可以直接編寫你的SQL查詢,並投影到你的ViewModel而不是匿名類型(我認爲這是一個好習慣),所以創建一個名爲PartyViewModel的類,查看你以後,和你的手工製作的SQL

 
//use your optimized SQL query that you write or even call a stored procedure 
db.Database.SQLQuery("select * from .... join .... on"); 

我寫一個關於blog post圍繞EF這些問題,使用它。這篇文章還沒有完成,但總而言之,只要有耐心,使用一些這些技巧,觀察它們的效果(並測量它),你就會達到你想要的。