2017-08-26 69 views
0

@EDIT 我按照Fastest Way of Inserting in Entity Framework的步驟操作,結果變得更糟,所以它不是重複的。使用實體框架將大量行插入到數據庫中

我的目標是創建一個種子方法來填充LocalDb的其中一個表。該方法將添加182500行(模擬500個設備的年度活動數據)以供進一步測試。我可能想再運行幾次來更改設備的數量,因此會生成更多的行。這就是爲什麼我需要儘可能高效地插入行。

protected void SeedReportDataTable(int numberOfTerminals) 
    { 
     var rand = new Random(); 
     var tidsList = new List<string>(); 

     // generuj liste losowych numerow tid 
     for (int i = 0; i < numberOfTerminals; i++) 
     { 
      var randomTid = rand.Next(100000, 1000000).ToString(); // generuj 6-cyfrowy numer tid 
      while (tidsList.Contains(randomTid)) { randomTid = rand.Next(100000, 1000000).ToString(); } // elminuj powtorzenia 
      tidsList.Add(randomTid); 
     } 

     // dla kazdego z numerow tid generuj roczna historie aktywnosci 
     var recordsList = new BlockingCollection<ReportData>(); 
     int year = Convert.ToInt32(DateTime.Now.Year); 

     Parallel.ForEach(tidsList, tid => 
     { 
      // dla kazdego miesiaca 
      for (int month = 1; month <= 12; month++) 
      { 
       // dla kazdego dnia 
       for (int day = 1; day <= DateTime.DaysInMonth(year, month); day++) 
       { 
        var record = new ReportData 
        { 
         Tid = tid, 
         Active = Convert.ToBoolean(
          rand.Next(0, 11)), // generuj losowy stan aktywnosci z prawdopodbienstwem 1/10 na bycie nieaktywnym 
         Date = new DateTime(year, month, day) 
        }; 
        recordsList.Add(record); 
       } 
      } 
     }); 
     // dodaj unikalne klucze glowne rekordom przed dodaniem do kontekstu bazy 
     var keyValue = 1; 

     foreach (var record in recordsList) 
     { 
      record.Id = keyValue++; 
     } 

     // podziel liste na czesci 
     int chunkSize = 1000; 

     for (int recordsSkipped = 0; recordsSkipped < recordsList.Count; recordsSkipped += chunkSize) 
     { 
      // wymieniaj kontekst 
      using (var db = new dbEntities()) 
      { 
       db.Configuration.AutoDetectChangesEnabled = false; 
       db.Configuration.ValidateOnSaveEnabled = false; 
       // dodawaj do bazy po kawalku 
       db.ReportData.AddRange(recordsList.Skip(recordsSkipped).Take(chunkSize)); 
       db.SaveChanges(); 
      } 
     } 
    } 

運行此代碼需要30分鐘才能完成。在此之前,我跑了一個版本結束:

using (var db = new dbEntities()) 
{ 
    db.ReportData.AddRange(recordsList); 
    db.SaveChanges(); 
} 

並花了15分鐘,這仍然比我預期的要慢。

爲什麼我的「改進」失敗?

我能做些什麼來使插入行更快?

+3

[實體框架中插入的最快的方法]的可能的複製(https://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework) –

+0

你要在生產或Sql Server中使用LocalDB?如果你擔心生產性能,那麼你應該對Sql Server進行基準測試,如果這是在生產中運行的。 – Igor

+2

這就是說使用EF爲許多記錄播種數據庫並不是最高性能的選擇。考慮使用Sql Bulk Insert,而不是在插入大量記錄(數百萬或更多)時性能至關重要。即使這樣你也應該檢查Sql Server的瓶頸(即索引更新和跨插入的統計更新也會減慢這樣的批處理工作)。 – Igor

回答

0

當我將播種方法添加到Configuration.cs並運行update-database命令時,插入所有行所用的時間少於5分鐘。

僅在調用Context.AddRange()一次時纔有效。

 dbContext.Configuration.AutoDetectChangesEnabled = false; 
     dbContext.Configuration.ValidateOnSaveEnabled = false; 
     dbContext.ReportData.AddRange(recordsList); 
     dbContext.SaveChanges(); 
相關問題