2017-09-29 22 views
3

我正在研究實用程序來讀取我已經給出的JSON文件並將其轉換爲SQL Server。我選擇的武器是一個.NET Core控制檯應用程序(我試圖用.NET Core來完成我所有的新工作,除非有令人信服的理由)。我把所有的東西都「工作」了,但是在某個地方顯然存在問題,因爲這些表現真的很可怕,幾乎無法使用。JSON數組到實體框架核心非常慢?

JSON文件大約爲27MB,包含214個元素的主數組,每個數組都包含兩個字段以及150-350條記錄的數組(該數組有幾個字段並可能包含一個小的< 5條記錄數組或兩個)。總記錄大約是35,000。

在下面的代碼中,我更改了一些名稱並刪除了一些字段以使其更具可讀性,但所有實際工作的邏輯和代碼都沒有改變。

請記住,我已經做了大量的測試,調用SaveChanges()的位置和次數,最初認爲Db的次數是問題。儘管下面的版本在214-記錄循環的每次迭代中調用SaveChanges()一次,但我試着將它移到整個循環結構之外,並且沒有明顯的性能變化。換句話說,在Db爲零的情況下,這仍然很慢。你問的速度有多慢,24小時運行如何擊中你?我願意在這一點上嘗試任何東西,我甚至考慮將整個過程轉移到SQL Server中,但是在C#中工作比在TSQL中工作得多。

static void Main(string[] args) 
{ 
    string statusMsg = String.Empty; 

    JArray sets = JArray.Parse(File.ReadAllText(@"C:\Users\Public\Downloads\ImportFile.json")); 
    try 
    { 
     using (var _db = new WidgetDb()) 
     { 
      for (int s = 0; s < sets.Count; s++) 
      { 
       Console.WriteLine($"{s.ToString()}: {sets[s]["name"]}"); 

       // First we create the Set 
       Set eSet = new Set() 
       { 
        SetCode = (string)sets[s]["code"], 
        SetName = (string)sets[s]["name"], 
        Type = (string)sets[s]["type"], 
        Block = (string)sets[s]["block"] ?? "" 
       }; 
       _db.Entry(eSet).State = Microsoft.EntityFrameworkCore.EntityState.Added; 

       JArray widgets = sets[s]["widgets"].ToObject<JArray>(); 
       for (int c = 0; c < widgets.Count; c++) 
       { 
        Widget eWidget = new Widget() 
        { 
         WidgetId = (string)widgets[c]["id"], 
         Layout = (string)widgets[c]["layout"] ?? "", 
         WidgetName = (string)widgets[c]["name"], 
         WidgetNames = "", 
         ReleaseDate = releaseDate, 
         SetCode = (string)sets[s]["code"] 
        }; 

        // WidgetColors 
        if (widgets[c]["colors"] != null) 
        { 
         JArray widgetColors = widgets[c]["colors"].ToObject<JArray>(); 

         for (int cc = 0; cc < widgetColors.Count; cc++) 
         { 
          WidgetColor eWidgetColor = new WidgetColor() 
          { 
           WidgetId = eWidget.WidgetId, 
           Color = (string)widgets[c]["colors"][cc] 
          }; 
          _db.Entry(eWidgetColor).State = Microsoft.EntityFrameworkCore.EntityState.Added; 
         } 
        } 

        // WidgetTypes 
        if (widgets[c]["types"] != null) 
        { 
         JArray widgetTypes = widgets[c]["types"].ToObject<JArray>(); 

         for (int ct = 0; ct < widgetTypes.Count; ct++) 
         { 
          WidgetType eWidgetType = new WidgetType() 
          { 
           WidgetId = eWidget.WidgetId, 
           Type = (string)widgets[c]["types"][ct] 
          }; 
          _db.Entry(eWidgetType).State = Microsoft.EntityFrameworkCore.EntityState.Added; 
         } 
        } 

        // WidgetVariations 
        if (widgets[c]["variations"] != null) 
        { 
         JArray widgetVariations = widgets[c]["variations"].ToObject<JArray>(); 

         for (int cv = 0; cv < widgetVariations.Count; cv++) 
         { 
          WidgetVariation eWidgetVariation = new WidgetVariation() 
          { 
           WidgetId = eWidget.WidgetId, 
           Variation = (string)widgets[c]["variations"][cv] 
          }; 
          _db.Entry(eWidgetVariation).State = Microsoft.EntityFrameworkCore.EntityState.Added; 
         } 
        } 
       } 
       _db.SaveChanges(); 
      } 
     } 

     statusMsg = "Import Complete"; 
    } 
    catch (Exception ex) 
    { 
     statusMsg = ex.Message + " (" + ex.InnerException + ")"; 
    } 

    Console.WriteLine(statusMsg); 
    Console.ReadKey(); 
} 
+0

LINQ的-2-SQL是另一種選擇。問題可能是它在後端對數據庫進行單獨插入。你打開EntityFramework的日誌記錄功能嗎?只需連線到'Console.Out' –

+0

哪一行是最慢的?你是否試圖用調試器來發現它? –

+0

你說甚至沒有調用'SaveChanges'也很慢?如何評論所有'_db.Entry(...'行?仍然很慢? –

回答

2

我有這樣的代碼,大量的循環和噸變化的狀態問題。

在_db上下文中進行的任何更改/操作都會生成它的「跟蹤」。而且每次都會讓你的上下文更慢。閱讀更多here

對我來說,修正是在一些關鍵點上創建新的EF上下文(_db)。它爲我節省了幾個小時的運行時間!

你可以嘗試在此循環

創建_db每次迭代的新實例,包含214元

的主陣列如果作出任何改變,嘗試一些stopwatch增加得到什麼/在哪裏需要這麼長時間的最佳想法。

+0

熱潮! 24小時以上不到24分鐘!我刪除了用於Db上下文的使用塊,並在外部for循環內部實例化它,並在調用Save Changes()後立即將其放置在最後。謝啦! –

+0

很高興幫助:) – Iannick

0

如果您要進行數千次更新,那麼EF並不是真的要走的路。像SQLBulkCopy這樣的東西將做的伎倆。

您可以嘗試bulkwriter庫。

IEnumerable<string> ReadFile(string path) 
{ 
using (var stream = File.OpenRead(path)) 
    using (var reader = new StreamReader(stream)) 
    { 
     while (reader.Peek() >= 0) 
     { 
       yield return reader.ReadLine(); 
     } 
    } 
} 

var items = 
    from line in ReadFile(@"C:\products.csv") 
    let values = line.Split(',') 
    select new Product {Sku = values[0], Name = values[1]}; 

然後

using (var bulkWriter = new BulkWriter<Product>(connectionString)) { 
    bulkWriter.WriteToDatabase(items); 
}