2014-03-06 17 views
5

在我的應用程序(EF6 + SQL Server)中,我動態創建EF查詢以啓用豐富的搜索功能。與原始SQL執行時間相比,實體框架的性能開銷是多少?

這些查詢是通過鏈接一堆Where()謂詞並將結果使用少量聚合投影到已知的CLR類型中來創建的。在所有情況下,EF生成一個返回少量結果(大約10)的單個SQL查詢。

使用SQL事件探查器我可以看到,這些生成的查詢執行時間由數據庫執行幾毫秒。但是,除非查詢非常簡單,否則總執行時間(從我的代碼調用ToList()或Count())在幾百毫秒內!該代碼構建在發佈模式下,並且未經調試器測試。

任何人都可以給我任何提示什麼可能是我的方法錯了嗎?與原始SQL執行時間相比,EF的開銷是否有可能在時間上是兩個數量級?

編輯:

這些是我使用的篩選結果集的一些代碼樣品:

if (p.PriceMin != null) 
    query = query.Where(a => a.Terms.Any(t => t.Price >= p.PriceMin.Value)); 

if (p.StartDate != null && p.EndDate != null) 
    query = query.Where(a => a.Terms.Any(t => t.Date >= p.StartDate.Value && t.Date <= p.EndDate.Value)); 

if (p.DurationMin != null) 
    query = query.Where(a => a.Itinerary.OfType<DayElement>().Count() > p.DurationMin.Value - 2); 

if (p.Locations != null && p.Locations.Count > 0) 
{ 
    var locs = p.Locations.Select(l => new Nullable<int>(l)).ToList(); 
    query = query.Where(a => a.Itinerary.OfType<MoveToElement>().Any(e => locs.Contains(e.LocationId)) || 
     a.Itinerary.OfType<StartElement>().Any(e => locs.Contains(e.LocationId)) || 
     a.Itinerary.OfType<EndElement>().Any(e => locs.Contains(e.LocationId))); 
} 

然後我命令的結果是這樣的:

if (p.OrderById) 
    query = query.OrderBy(a => a.Id); 
else if (p.OrderByPrice) 
    query = query.OrderByDescending(a => a.Terms.Average(t => t.Price)); 

的執行時間大致相同,如果我試圖連續多次執行相同的查詢(使用相同的DbContext調用多個query.Count()),所以我想在這種情況下,EF的查詢生成是非常有效的ient。看起來其他東西是瓶頸......

+0

我在這裏看到了同樣的事情。我使用原始SQL查詢('Database.SqlQuery <>'),幾乎總是隻返回一行。 – Cameron

+0

@Cameron你有沒有想過你的情況是什麼問題? –

+0

不,對不起。我懷疑EF的開銷很高。我最終拋棄了EntityFramework而轉而使用Dapper(我極力推薦它)。我曾經使用過的最好的ORM(缺乏更好的術語)。儘管如此,原始SQL仍然太慢了(儘管現在瓶頸是服務器而不是客戶端),並且我最終放棄了SQL Server for SQLite(這很好,除非你有高流量的數據),然後最終拋棄對於我自己編寫的專用嵌入式SQL引擎。 – Cameron

回答

5

一般來說,是的EF比原始SQL慢,因爲很難預測EF如何建立查詢,而EF不知道數據庫索引或它是如何結構化的。

沒有辦法確切地說開銷是多少,因爲它會因查詢而異。 如果你想用EF優化你的查詢,你將不得不嘗試各種鏈接你的where謂詞和基準結果的方法。即使最細微的差異也可以產生很大的差異。

我遇到了一個問題,我在那裏有使用.Any().Contains(),你可以看到這裏的巨大差異:Check if list contains item from other list in EntityFramework

的結果是一樣的,但第二個查詢要快100倍左右。所以是的,對於某些查詢,EF可能比原始SQL慢兩個數量級。其他時間會稍慢幾毫秒。

+1

看來這裏的問題不在構建SQL查詢中。 EF快速構建這些查詢(最多幾毫秒)。由EF構建的查詢雖然很複雜,但在直接從SSMS執行時也非常快。然而,當EF自己執行這些查詢時,速度會降低100倍 - 這沒什麼意義...... –

+0

我發現EF在實體跟蹤方面的開銷很大。當你只是在讀取時,嘗試使用AsNoTracking等。 – jocull

+0

@jocull我已經嘗試將ProxyCreationEnabled和AutoDetectChangesEnabled都設置爲false的AsNoTracking,但結果是相同的... –

0

根據documentation它取決於您是第一次還是第二次運行唯一查詢。這取決於您的基準代碼。你應該

  1. 執行查詢首次
  2. 啓動秒錶
  3. 執行查詢第二次
  4. 停止秒錶
相關問題