Konsolenanwendung verlangsamt im Laufe der time

Ich versuche, etwa 900K Zeilen von data zu importieren und es meinem neuen datamodell zuzuordnen. Mein Problem ist, dass die Konsolenanwendung, die ich für diese Importfunktionalität aufgebaut habe, im Laufe der time verlangsamt wird.

Ich habe die SQL-Abfragen überwacht und sie alle gut (<5ms). Ich habe versucht, kleinere Stücke zu importieren, fx 1K Zeilen, zu einer time. Die Stoppuhr-Timings sieht so aus:

  • Anzahl: 100 | Avg ms: 36.
  • Anzahl: 200 | Avg ms: 67
  • Anzahl: 300 | Avg ms: 106
  • Anzahl: 400 | Avg ms: 145
  • Anzahl: 500 | Avg ms: 183
  • Anzahl: 600 | Avg ms: 222
  • Anzahl: 700 | Avg ms: 258
  • Anzahl: 800 | Avg ms: 299
  • Anzahl: 900 | Avg ms: 344
  • Anzahl: 1000 | Avg ms: 376

Beim Neustart der Anwendung mit einem neuen Stück von 1K Zeilen sind die Timings ähnlich.

Die Importdaten haben folgendes Format:

public class ImportData { public int Id { get; set; } public int TaxpayerId { get; set; } public string CustomerName { get; set; } public string Email { get; set; } public string PhoneNumber { get;set; } } 

Ein vereinfachtes Beispiel für mein datamodell sieht so aus:

 public class Channel { public int Id { get; set; } public string Name { get; set; } } public class Permission { public Guid Id { get; set; } public Channel Channel { get; set; } public string Recipient { get; set; } } public class Taxpayer { public Guid Id { get; set; } public int TaxpayerId { get; set; } public string Name { get; set; } public List<Permission> Permissions { get; set; } } 

Meine Importmethode sieht so aus:

 public void Import() { Stopwatch stopwatch = new Stopwatch(); //Get import data List<ImportData> importDataList = _dal.GetImportData(); stopwatch.Start(); for (int i = 0; i < importDataList.Count; i++) { ImportData importData = importDataList[i]; Taxpayer taxpayer = new Taxpayer() { Name = importData.CustomerName, TaxpayerId = importData.TaxpayerId, Permissions = new List<Permission>() }; //Does not call SaveChanges on the context CreateTaxpayer(taxpayer, false); //Create permissions if (!string.IsNullOrWhiteSpace(importData.Email)) { //Does not call SaveChanges on the context CreatePermission(_channelIdEmail, importData.Email, taxpayer, PermissionLogType.PermissionRequestAccepted); } if (!string.IsNullOrWhiteSpace(importData.PhoneNumber)) { //Does not call SaveChanges on the context CreatePermission(_channelIdPhoneCall, importData.PhoneNumber, taxpayer, PermissionLogType.PermissionRequestAccepted); //Does not call SaveChanges on the context CreatePermission(_channelIdSms, importData.PhoneNumber, taxpayer, PermissionLogType.PermissionRequestAccepted); } if ((i + 1) % 100 == 0) { Console.WriteLine("Count: " + (i + 1) + " | Avg ms: " + stopwatch.ElapsedMilliseconds / 100); stopwatch.Restart(); } } _dal.SaveChanges(); } 

Ich habe folgendes versucht:

  • reduziere die Anzahl der Anrufe in SaveChanges (nur einmal am Ende angerufen)
  • implementieren Multithreading (ohne Glück) – es scheint nicht Hand in Hand mit Entity Framework gehen

Ich komme hier aus. Haben Sie Jungs irgendwelche Vorschläge, um diese performance Problem zu lösen?

Warum nimmst du nicht BulkCopy, dieser Code muss eine Änderung für deine Tabellen und Spalten benötigen, aber hoffentlich bekommst du die Idee:

 using (var bulkCopy = new SqlBulkCopy(_DbContext.Database.Connection.ConnectionString, SqlBulkCopyOptions.TableLock)) { bulkCopy.BulkCopyTimeout = 1200; // 20 minutes bulkCopy.BatchSize = 10000; bulkCopy.DestinationTableName = "TaxPayer"; var table = new DataTable(); var props = TypeDescriptor.GetProperties(typeof(TaxPayer)) //Dirty hack to make sure we only have system data types //ie filter out the relationships/collections .Cast<PropertyDescriptor>() .Where(propertyInfo => propertyInfo.PropertyType.Namespace.Equals("System")) .ToArray(); foreach (var propertyInfo in props) { bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name); table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType); } // need to amend next line to account for the correct number of columns var values = new object[props.Length + 1]; foreach (var item in importDataList) { for (var i = 0; i < values.Length - 1; i++) { ///TODO: Decide which columns need including values[i] = props[i].GetValue(item); } table.Rows.Add(values); } bulkCopy.WriteToserver(table); }