今天發現網站的速度慢的出奇,當時用EF的時候也沒怎麼注意,載入資料時隨心所欲,對EF的原理不是很清楚。使用EF的目的只有一個,那就是快!
下面也是在網上搜到的一些內容,進行了整合。有些說的也不一定對,望路過者給點補充。
在EF下有三個對象IQueryable,IEnumerable以及IList,這些介面都可以使用資料查詢操作,但是有一些問題需要明白。
http://www.cnblogs.com/hiteddy/archive/2011/10/01/Difference_among_IQueryable_IEnumeralb_IList_in_Entity_Framework.html
IEnumerable對象一旦AsEnumerable後總是需要到資料庫中擷取資料來源,
(每次都如此),然後把資料來源載入到記憶體中後,再執行Linq to Object的操作,所以後續就只在記憶體中完成了。
IQueryable對象則更嚴重,幾乎每個資料操作都會到資料庫中擷取資料,但是它可以把這些操作組成一個複雜的運算式,一次完成。也就是說,它會把這些查詢操作記下來,到真正索取資料時一下子都返回,這會產生一個很複雜的sql語句,不過sql server都有計劃任務,肯定會被最佳化的。
IList資料,基本上只要ToList了,馬上就會載入資料來源,以後的操作就跟資料庫沒關了,全部在記憶體中完成。
一個效能殺手:
http://www.cnblogs.com/dudu/archive/2012/04/01/enitity_framework_func.html
在IQuerable中使用Func參數,會引起的資料庫全表查詢。如
public List<Steel> GetOne(Func<T, bool> predicate){
this.context.Steels.Where(predicate).ToList();
}
將會導致Steel全表查詢,將整個資料集載入到記憶體中。
原因是以上操作會導致this.context.Steels轉換為IEnumerable,這就意味著一次AsEnumrable方法調用,致使載入所有資料集到記憶體中。
解決辦法是把predicate參數換成Expression<Func<T,bool>> predicate即可。這樣的話會使用IQueryable方法調用Where語句。
這裡要強調的是,上述GetOne裡的Where語句,可以是IEnumerable的Where方法,也可以是IQueryable的Where方法。this.Context.Steels是
DbSet對象,該對象實現了IEnumerable和IQueryable介面,故Where語句裡的參數是Func還是Expression將決定DbSet對象的轉換。
使用MiniProfiler進行效能調試
這個工具在MVC和EF架構的網站中,非常適用檢驗網站效能。使用NuGet下載MiniProfiler和MiniProfilerEF,具體過程可以在網上搜下。我在使用時遇到的一個問題是,總是輸不出調試資訊來。使用EF4.1以後的版本可以解決這個問題,所以如果你調試的不順利,建議升級EF到4.3,應該不會出錯了。
我使用MiniProfiler檢查出大量由於LazyLoading帶來的效能問題,有時候一個資料量較多的頁面,sql請求可能超過上百個。LazyLoading並不總是那麼好,對於在網頁中總是要顯示的資料,不妨一下子都載入進來,然後在記憶體中找到需要的資料再使用。