2016-11-10 171 views
4

我們有一個需要大約10秒才能完成的EF4查詢。該查詢並不複雜,但由於包含很多相關表格,所以需要很長時間。我試圖加快速度。爲什麼這個EF查詢需要這麼長時間?

原始查詢看起來是這樣的(簡稱爲清楚起見)...

var supportTickets = ctx.SupportTickets 
    .Include(s => s.System.Customer.Country) 
    .Include(s => s.System.Site.Address.Country) 
    // other includes omitted 
    .OrderByDescending(s => s.ID) 
    .ToList(); 
var ticketsList = supportTickets 
    .Select(CreateSupportTicketListOverview) 
    .ToList(); 

CreateSupportTicketListOverview()是採取實體和返回基於它DTO的方法。它的縮短版本看起來像這樣...

private static SupportTicketListOverview CreateSupportTicketListOverview(SupportTicket x) 
    { 
    return new SupportTicketListOverview { 
     ID = x.ID, 
     SystemNumber = x.System != null ? x.System.SystemNumber : "", 
     CustomerName = x.System != null && x.System.Customer != null ? x.System.Customer.Name : "", 
     ShortSummary = x.ShortSummary, 
     SiteName = x.Site != null ? x.Site.SiteName : "", 
     Status = x.Status != null ? x.Status.Description : "", 
     // other properties omitted for clarity 
    }; 
    } 

正如我所說,這需要大約10秒,並返回剛剛結果不到4000。 SQL Server Profiler顯示查詢花費了大約6.6秒。如果我們複製生成並自行運行的SQL,它只需要大約2秒鐘,這使我感到困惑。爲什麼自行運行時速度更快?創建實體所需的時間不會包含在數據庫查詢中嗎?如果是這樣,那麼剩下的時間花在做什麼?

我試圖通過關閉跟蹤並從數據庫中提取所需的數據而不是完整的實體來改善這一點。修改後的代碼看起來像這樣(爲了清晰再次縮短)...

var tickets = ((SalesTrackerCRMEntities) getContext()).SupportTickets 
     .AsNoTracking() 
     .Include(s => s.System.Customer.Country) 
     .Include(s => s.System.Site.Address.Country) 
     .OrderByDescending(s => s.ID) 
     .Select(t => new { 
     SystemNumber = t.System != null ? t.System.DHRNumber : "", t.ID, 
     CustomerName = t.System != null && t.System.Customer != null ? t.System.Customer.Name : "", 
     SiteName = t.Site != null ? t.Site.SiteName : "", 
     Status = t.Status != null ? t.Status.Description : "", 
     // other stuff omitted 
     }) 
     .AsEnumerable(); 
    var tickets1 =tickets 
     .Select(t => new SupportTicketListOverview { 
     ID = t.ID, 
     SystemNumber = t.SystemNumber, 
     CustomerName = t.CustomerName, 
     ShortSummary = t.ShortSummary, 
     SiteName = t.SiteName, 
     Status = t.Status, 
     // other stuff omitted 
     }) 
     .ToList(); 

令我吃驚的是,這花了大約15秒鐘才完成。在剖析器中,數據庫查詢本身花費了大約0.7s,即比原始查詢快的十倍,但EF查詢總體花費了50%較長的

所以我完全困惑。我做了一些搜索,但是我發現的所有建議都是針對我已經在做的事情。例如,this blog post提供了七種提高EF性能的方法。這些包括不使用存儲庫模式(不確定他在這裏的意思,因爲他沒有顯示任何如何做或不做的例子),不使用分頁(我們沒有),使用預測(我們是,至少在新的查詢中),關閉延遲加載(它已經關閉),關閉跟蹤(已經完成)並在表上使用索引(我們已經是)。最後的技巧是減少查詢次數。由於我們需要所有相關數據,因此無法看到我們在這裏如何做到這一點。

總之,原始數據庫查詢需要6.6s,整個EF查詢需要10s。修改後的查詢需要數據庫部分爲.7s,而整個EF查詢需要15s。所有這些都太長了。

是否有人能夠建議我如何加快查詢?謝謝

+0

您的數據庫服務器位於其他地區嗎?當我的azure web應用程序在美國地區託管並且我的數據庫(錯誤地)在巴西地區時,我有(類似)類似的問題。 – Developer

+1

您的表訪問正確索引? EF4在組裝一個體面的查詢方面很糟糕。 –

+2

http://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet – Hackerman

回答

0

你正在使用什麼版本的SQL Server?如果是2016年,您可以啓用Query Store(https://msdn.microsoft.com/en-us/library/dn817826.aspx)並查找EF4查詢正在執行的t-sql查詢。如果它的版本較舊,則可以在EF4查詢運行時使用此(http://blog.sqlauthority.com/2009/01/07/sql-server-find-currently-running-query-t-sql/)來查找查詢文本,並查看爲什麼查詢速度較慢,方法是針對服務器運行並分析計劃/缺失索引/等。

+0

謝謝,但正如我在我原來的問題中所說的,如果我們將SQL複製到SSMS中,它只需要大約2秒鐘運行,所以這不是問題。 –

相關問題