2016-08-12 81 views
0

我想讓我的asp.net WebAPI Web服務讀取.csv並使用實體框架更新數據庫。 .csv文件約爲20,000-30,000行。WebAPI EF更新30,000行數據很慢

截至目前我正在使用TextfieldParser來讀取.csv.csv文件的每一行我創建一個新的對象,然後將對象添加到EF上下文中。

一旦完成將所有行的情況下,然後我打電話db.SaveChanges();

看着我注意到它要求每行......這需要很長的時間的更新語句控制檯。有沒有更好的方法來實現這一目標?

if (filetype == "xxx") 
{ 
    using (TextFieldParser csvReader = new TextFieldParser(downloadFolder + fileName)) 
    { 
     csvReader.SetDelimiters(new string[] { "," }); 
     csvReader.HasFieldsEnclosedInQuotes = true; 

     int rowCount = 1; 

     while (!csvReader.EndOfData) 
     { 
      string[] fieldData = csvReader.ReadFields(); 

      //skip header row 
      if (rowCount != 1) 
      {       
       var t = new GMI_adatpos 
         { 
          PACCT = fieldData[3] 
         }; 

       db.GMI_adatpos.Add(t); 
      } 

      rowCount++; 
     } 
    } 
} 

db.SaveChanges(); 
+0

Update語句?這應該會生成插入語句。什麼是「很長一段時間」?你不會在眨眼之間得到它。你現實的期望是什麼? –

回答

1

這個問題是很常見的,

在你的情況,我們可以把它分爲兩個類別:

  • 添加VS的AddRange性能
  • 寫&數據庫往返

Add vs AddRange Performan ce

Add方法將嘗試在每次添加新記錄時檢測更改,而AddRange只執行一次。每次檢測到更改可能需要幾分鐘的時間。

這個問題很容易修復,只需創建一個列表,將實體添加到該列表中,並在末尾使用帶有列表的AddRange。

List<GMI_adatpo> list = new List<GMI_adatpo>(); 

if (filetype == "xxx") 
{ 
    using (TextFieldParser csvReader = new TextFieldParser(downloadFolder + fileName)) 
    { 
     csvReader.SetDelimiters(new string[] { "," }); 
     csvReader.HasFieldsEnclosedInQuotes = true; 

     int rowCount = 1; 

     while (!csvReader.EndOfData) 
     { 
      string[] fieldData = csvReader.ReadFields(); 

      //skip header row 
      if (rowCount != 1) 
      {       
       var t = new GMI_adatpos 
         { 
          PACCT = fieldData[3] 
         }; 

       list.Add(t); 
      } 

      rowCount++; 
     } 
    } 
} 

db.GMI_adatpos.AddRange(list) 
db.SaveChanges(); 

寫&數據庫往返

每次你保存記錄,你執行一個數據庫往返。因此,如果插入平均30,000條記錄,則執行30,000次數據庫往返是瘋狂的!

免責聲明:我是這個項目的所有者Entity Framework Extensions

這個庫允許執行:

  • BulkSaveChanges
  • BulkInsert
  • BulkUpdate
  • BulkDelete
  • BulkMerge

您既可以調用BulkSaveChanges而不是SaveChanges,也可以創建一個列表來插入並直接使用BulkInsert來取得更高的性能。

BulkSaveChanges解決方案(辦法比的SaveChanges快)

db.GMI_adatpos.AddRange(list) 
db.SaveChanges(); 

BulkInsert解決方案(最快比BulkSaveChanges但不保存相關實體)

db.BulkInsert(list); 
+0

感謝喬納森...列表減少了約30-40%的處理時間,您的項目EntityFrameworkExtension縮短了約90-95%的時間。謝謝! – solarissf

1

由於添加到DbContext的項目數非常多,所以ram空間逐漸被填滿,操作非常緩慢。因此,最好在幾條記錄(例如100)之後調用SaveChanges Methods並更新DbContext。

if (filetype == "xxx") 
{ 
    using (TextFieldParser csvReader = new TextFieldParser(downloadFolder + fileName)) 
    { 
     csvReader.SetDelimiters(new string[] { "," }); 
     csvReader.HasFieldsEnclosedInQuotes = true; 

     int rowCount = 1; 

     while (!csvReader.EndOfData) 
     { 
      if(rowCount%100 == 0) 
      { 
       db.Dispose(); 
       db.SaveChanges(); 
       db = new AppDbContext();//Your DbContext 
      } 

      string[] fieldData = csvReader.ReadFields(); 

      //skip header row 
      if (rowCount != 1) 
      {       
       var t = new GMI_adatpos 
         { 
          PACCT = fieldData[3] 
         }; 

       db.GMI_adatpos.Add(t); 
      } 

      rowCount++; 
     } 
    } 
} 
+0

謝謝穆罕默德,這減少了約30-40%的時間 – solarissf