程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 一次EF批量插入多表數據的性能優化經歷,ef插入性能優化

一次EF批量插入多表數據的性能優化經歷,ef插入性能優化

編輯:C#入門知識

一次EF批量插入多表數據的性能優化經歷,ef插入性能優化


  距離上次的博客已經有15個多月了,感慨有些事情還是需要堅持,一旦停下來很有可能就會停很久或者從此再也不會堅持。但我個人一直還堅持認為屬於技術狂熱份子,且喜歡精益求精的那種。最近遇到兩個和數據遷移相關的項目,均遇到需要性能優化的問題,這裡拿第二個項目的一個小優化過程與大家分享,技術並不高深,我注重的是解決問題的過程。我的方案是有業務背景以及技術背景限制的,不一定適合其它項目,優化是相對的。


  業務場景:我們需要遷移一批老的合同訂單數據,其有一個合同的訂單數為519條,遷移到新表中會涉及到主要的4個表,就是說519條老數據,會變成519*4。
 
  技術背景:數據庫是mysql,後台采用的是微軟的EF


 


  問題:遷移這批訂單當時最好的性能方案是14秒(未優化前是分鐘級別),我們總共有400000訂單,算下最理想狀態下的總時間:=(14/519)*400000/3600=3小時,再算下取數據,轉換數據的時間,基本要4小時。如果中途有異常,這個時間可能需要一夜甚至更長的時間才能遷移完,這真正惡夢。
 
  先來看看優化前:優化前導519個合同是分鐘級別的,看下代碼後我的方案是分三步:


  1:按批次,比如10個合同一批來操作,將後續需要的數據全部取出來。原方案是用到哪查到哪,試想400000的訂單還不查個一天兩天的。
  2:轉換數據,將源數據轉換成新的對象集合,此處不操作數據庫。
  3:批量插入數據,將轉換後校驗無誤的數據導入數據庫,原方案是邏輯到哪,哪就插入數據庫。不便於定位性能瓶頸也不方便進行有針對性的優化。
 
  根據以上三個步驟,我們就很容易精確定位是哪方面慢了,是查詢數據庫慢,轉換數據慢,還是插入數據庫慢。
 
  經過此方面調整後的結果:
  1:一次性讀取數據後,性能明顯提升,降低了數據庫讀取次數,享受到了批量取數據的好處;
  2:定位到性能瓶頸在於數據庫插入,總時間15秒,保存數據花了14秒


 


  疑惑:我對保存519*4條數據需要14秒的結果不滿意,我堅定認為數據庫插入如此小數量級的數量不需要這麼長的時間。再次分析,發現我們需要保存多張表的數據,且相互之間存在依賴關系,即第二張表的數據需要第一張表插入後的主鍵,這樣我們在寫EF時,會出現多條SaveChange的方法。519個訂單做循環,SaveChange的總次數:519*3。
 
  改造:分三次數據庫操作
  1:先全量保存第一個被依賴的表,此時由於EF的數據追蹤功能,插入數據庫後,對象上會自動賦值主鍵信息;
  2:再全量保存第二個被依賴的表,由於被依賴的表在第一步已經更新成功,此處能夠成功獲取到外鍵;
  3:最後全量保存第三被依賴的表。


 


  此方案的SaveChange次數降低到3次,執行時間變更5.5秒,性能提高接近200%。
 
 
  數據庫事務,如果我們的操作加上事務會怎樣?我們從優化前的版本開始看(不是上面提到的分打開三次數據庫批量操作):主要利用TransactionScope來完成

using (var trans = new TransactionScope(TransactionScopeOption.Required,
                   new TransactionOptions()
                   {
                       Timeout = new TimeSpan(0, 0, 240),
                       IsolationLevel =
                           System.Transactions.IsolationLevel.RepeatableRead
                   }))


  1:519*3次SaveChange,最外層嵌套一個大事務,不嵌套是58秒,嵌套了50秒,兩者相關不大,如果是一個DbContext出現大量的SaveChange,有事務從結果來看性能更優化,具體原因不明,待調查。
  2:519*3次SaveChange,縮小事務范圍,將事務放在循環體內部,結果變成14秒,看來小事務還是值得推薦的。
 
  再看改造後的分三次數據庫操作每次一次SaveChange的場景:外面嵌套一個大事務,嵌套是5.5秒,不嵌套是5.8,相差不大。


 


  單一職責,上面的批量插入數據庫使用了三次打開數據庫,每次只有一個SaveChange,那麼在一個DbContext中操作調用三次SaveChange呢?
  在一個DbContext中做三次SaveChange是32秒,采用三個DbContext分開操作是5.5秒,結論是大批量數據插入,避免在同一DbContext中做多次SaveChange。

 

 

  結論:

  1:避免使用大的數據庫事務,盡量控制在有需求時打開,不需要時及時關閉,它會鎖定資源的;

  2:批量插入表數據,盡量避免在同一DbContext下做多次SaveChange操作;

  3:如果有大批數據需要插入表,盡量采用單表集中插入後再操作後續表,避免插入一條數據SaveChange一次;

  4:讀取數據盡量按批量讀取,避免取一條數據讀取一次:查詢100次單條記錄與一次性查詢100條記錄是有很大差距的。
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved