Ado.net Entity FrameWork的效能問題

來源:互聯網
上載者:User

 

    當我們需要大批量追加資料,或者一次查詢海量資料的時候,必須注意,Ado.net Entity Framework的效率幾乎是無法忍受的。簡單的例子,我們將中國股市曆年的日線,約500萬條資料插入資料庫,使用Ado.net一般僅需要2分鐘左右,而使用EF,則這個時間會變為半小時的樣子。當我們要一次性的將所有資料讀取到記憶體的時候,這個效率同樣的令人難以忍受。所以,要注意以下要點:

 

1、使用Ado.net Entity,使用Esql效能略好,因為Linq To entities將首先轉換為esql再到sql語句。不過,我們多數的時候仍將使用Linq查詢,這樣相對來說知識能夠複用,而無需急於學習Esql。

2、如果是查詢一條記錄,用GetObjectByKey

    一般情況下,EF每次查詢都會從資料庫中擷取資料,不會使用緩衝,這樣效率較低。此時可以考慮使用GetObjectByKey,這樣,若該記錄已經在緩衝中則不會再次向資料庫發出Sql命令,不過如果該記錄

在緩衝中不存在,則會引發異常,所以我們通常使用TryGetObjectByKey

    using (QuoteEntities entity = new QuoteEntities())

   {

       object quote;

       EntityKey key = new EntityKey("Quote", "StockCode", "300001");

       entity.TryGetObjectByKey(key, out entity);

   }

 

3、如果無需對查詢的結果進行更新,則使用Notracking查詢,預設情況下系統預設的是MergeOption.AppendOnly

    using (QuoteEntities entity = new QuoteEntities())

   {

       Quote quote= entity.Quotes.Execute(MergeOption.NoTracking).Where(a => a.Stockcode == "300001").FirstOrDefault();

   }

4、如果某個查詢會多次使用,用先行編譯查詢:我們每次發出Linq To entities查詢的時候,系統會將其編譯為Esql,然後使用Provider轉換為相應資料庫的Sql語句,這個過程很長。

我們可以編譯好查詢,這樣EF會緩衝編譯的結果,這樣,後續的查詢就無需執行從linq到Esql再到Sql的轉換,速度會提高。

private static readonly Func<QuoteEntities, string ,User> CompiledQueryGetByStockCode =

CompiledQuery.Compile<QuoteEntities, string, User>((entity, stockCode) => entity.Quotes.Where(a=>a.StockCode == stockCode).FirstOrDefault());

然後,執行該查詢:

    using (QuoteEntities entity = new QuoteEntities())

   {

       Quote quote= CompiledQueryGetByStockCode.Invoke(entity, "300001");

   }

5、可以使用原生的Ado.net命令,但EF的Context中的Connection並不能直接利用,因為其預設為執行ESQL,那麼要直接執行Sql,包括如下三個命令:

        ObjectContext.ExecuteStoreCommand(),用來執行非Select的Sql命令。

        ObjectContext.ExecuteStoreQuery<T>(),用來執行Select的Sql命令,返回實體集合。

        ObjectContext.Translate<T>:這個是用來銜接Ado.net的,當你得到一個DbDataReader的時候,可以將結果轉換成實體集合。

        但實際上只有查詢比較有效。

6、批量insert的時候,只能使用原生Ado.net,自己根據Factory建立DbConnection對象和insert命令。當然,可以為DbCommand建立兩個擴充方法,添加參數和為參數賦值。當然,批量insert應該包裹在

事務中才能保證速度,否則一些資料庫預設是每insert一條就開啟一個事務,效能低下。我們可以每insert數萬條記錄才提交一次事務,速度會更快些。

7、在以效能為主的應用中,不建議使用EF的實體類,當然伴隨而來的,是不建議使用EF:

    在使用Sqlite追加資料的時候,在資源管理員中觀察檔案變化,檔案大小每次緩緩的增加4K的樣子,但是在不使用EF的實體物件而單純使用Ado.net的情形下,每次增加1M的樣子,要快得多。由此可見即使將資料讀入到EF的實體類,然後使用Ado.net直接insert到資料庫,效能的下降也在10倍以上,這或許和tracking有關。

     而使用原生Ado.net,常見的DbHelper方式和反射到實體類的方式,都有些奇怪。

     事實上,建立輕量級的DbHelper,只要為DbCommand命令建立兩個擴充方法處理參數問題,實體類實現一個IEntity介面(用於使用序號方式為各屬性Get或Set),再實現兩個擴充方法,即將DataReader返回的對象,轉換成實體類的IEnumerator,將實體物件轉換為DbParameter以作為insert、update的輸入參數,則資料訪問可簡單的實現。當然,為了避免寫太多Sql語句,為每個實體物件中加入insert、GetByKey之類的支援也是可行的。

    從這個角度來說,我們將實體物件和實體集合對象,混合在實體類中當然也是可行的,不過我們可以建立專門的對應類,繼承自訂的泛型Repository<實體>來處理,項目結構更為簡單,與資料庫有關的全部放在Data目錄下面。當然,由於實體物件需要建立才能執行其方法,因此涉及到實體物件集合的方法往往寫成靜態方法更合適。

    不過,考慮到軟體系統,什麼都無所謂,惟快不破,則EF實際上已經淡出視野,並無實際價值。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.