2014-11-04 157 views
2

我使用ASP NET MVC 4.5和EF6,代碼優先遷移。EF LINQ ToList非常慢

我有這個代碼,大約需要6秒。

var filtered = _repository.Requests.Where(r => some conditions); // this is fast, conditions match only 8 items 
var list = filtered.ToList(); // this takes 6 seconds, has 8 items inside 

我認爲這是因爲關係的,它必須建立他們的內部內存,但事實並非如此,因爲甚至當我返回0領域,它仍然是慢

var filtered = _repository.Requests.Where(r => some conditions).Select(e => new {}); // this is fast, conditions match only 8 items 
var list = filtered.ToList(); // this takes still around 5-6 seconds, has 8 items inside 

現在請求表是相當複雜的,大量的關係,並擁有16K〜項目。另一方面,過濾的列表應該只包含8個項目的代理。

爲什麼ToList()方法這麼慢?我實際上認爲問題不在於ToList()方法,但可能是EF問題,或者設計問題不好。

任何人都有過這樣的經驗嗎?

編輯:

這些條件:

_repository.Requests.Where(r => ids.Any(a => a == r.Student.Id) && r.StartDate <= cycle.EndDate && r.EndDate >= cycle.StartDate) 

所以基本上,我可以,如果Student ID是我的ID列表檢查和檢查,如果日期匹配。

+0

你是否在'some condition'中使用了任何導航屬性,因爲它導致了sql方面的連接? – dotctor 2014-11-04 11:00:22

+0

作爲@HamidP的附加,是否將您的導航屬性標記爲「虛擬」?否則,他們會立即加入,而不是延遲加載(糾正我,如果我錯了。) – Marthijn 2014-11-04 13:18:29

+0

是的,他們都是虛擬的。 – Jaanus 2014-11-04 13:23:00

回答

3

除了馬騰的答案,我認爲這個問題是關於兩個不同的情況

  1. some condition是複雜的,結果在複雜龐大的在你的數據庫連接或查詢

  2. some condition是在過濾列沒有索引,這會導致全表掃描並使查詢變慢。

我建議開始監測由實體框架生成查詢,這很簡單,你只需要設置上下文Log功能和看到的結果,

using (var context = new MyContext()) 
{ 
    context.Database.Log = Console.Write; 

    // Your code here... 
} 

如果你看到一些奇怪的生成的查詢嘗試通過將其部分分解來使其更好,有時候Entity Framework生成的查詢不太好。

如果查詢沒問題,那麼問題在於你的數據庫(假設沒有網絡問題)。

使用SQL事件探查器運行您的查詢並檢查出現了什麼問題。

UPDATE

我建議你:在你的餐桌

  1. 附加指數StartDateEndDate列(每一個,不是一個兩個)
+0

我在評論中添加了條件。 – Jaanus 2014-11-04 11:54:59

+0

什麼是IDS?整數列表?它的大小是多少? – dotctor 2014-11-04 11:57:42

+0

它可以從1到100左右不等,但即使有1個ID也很慢。它是學生ID上的整數列表。 – Jaanus 2014-11-04 12:00:47

2

ToList對數據庫執行查詢,而第一行不是。

你能在這裏顯示some conditions的代碼? 要提高性能,您需要優化數據庫表上的查詢/創建索引。

+0

我在評論中添加了條件。 – Jaanus 2014-11-04 11:53:41

+0

@Jaanus你能告訴你如何獲得'ids'? – 2014-11-04 15:18:00

5

filtered變量包含查詢這是一個問題,它不包含答案。如果您通過調用.ToList()來請求答案,即執行查詢時。這就是爲什麼它很慢的原因,因爲只有當您撥打.ToList()時,纔會執行您的數據庫查詢。

它被稱爲延期執行A google可能會給你一些關於它的更多信息。

如果您顯示了一些您的情況,我們可能會說出爲什麼它很慢。

+0

我在評論中添加了條件。 – Jaanus 2014-11-04 11:53:56

+0

如果你將'ids.Any(a => a == r.Student.Id)''改爲'ids.Contains(r.Student.Id)'',你能檢查它是否有效嗎?這仍然意味着你需要額外的表格。 'Student.Id'是關鍵還是索引? – Maarten 2014-11-04 12:05:49

+0

不是,它實際上是之前包含的,更改爲任何因爲我認爲它會使其更快。學生ID是整數,主鍵 – Jaanus 2014-11-04 12:29:17

0

Jaanus。此問題最可能的原因是實體框架生成的SQL查詢的可擴展性。我想你的過濾條件包含一些其他表的檢查。

嘗試檢查「SQL Server Profiler」生成的查詢。然後將此查詢複製到「Management Studio」並檢查「預計執行計劃」。作爲一項規則,「管理工作室」爲您的查詢生成索引建議嘗試遵循這些建議。

1

你的第一個代碼行僅返回IQueryable。這是您希望運行的查詢的表示,而不是查詢的結果。當您在IQueryable上調用.ToList()時,查詢本身僅在數據庫上運行,因爲它實際上是第一個要求輸入數據的點。

您的調整添加.Select只增加了現有的IQueryable查詢定義。它不會改變要執行的條件。你已經根本改變了以下內容,其中你回來8條:

select * from Requests where [some conditions]; 

喜歡的東西:

select '' from Requests where [some conditions]; 

你仍然必須執行與給你8條條件的完整的查詢,但對於每一個,你只要求一個空字符串,所以你回來8個空字符串。

長而短的一點是,您遇到的任何性能問題都來自您的「某些條件」。沒有看到它們,它很難知道。但是我曾經看到過去人們在調用.ToList()之前在循環內部添加了子句,並且無意中創建了大量複雜的查詢。

+0

我在評論中添加了條件。 – Jaanus 2014-11-04 11:58:59

+0

什麼類型是IDS?如果它是另一個IQueriable或List?如果它是一個IQueryable,你將重新評估它的請求表 – Keith 2014-11-04 13:35:14

+0

的每個記錄你也可以嘗試先運行日期比較,因爲它會很快,然後過濾是通過ID:_repository.Requests.Where(r => r.StartDate <= cycle.EndDate && r.EndDate> = cycle.StartDate).where(r => ids.Contains(r.Student.Id)); – Keith 2014-11-04 13:36:47