2016-01-20 12 views
5

Ho sviluppato un'applicazione client .NET WinForms. Questa applicazione viene utilizzata per popolare un database con migliaia di record. Per il livello dati ho usato EF6.Inserimento lento .NET nel database SQL Server remoto

Quando lavoro ed eseguo l'applicazione localmente, tutto funziona come previsto. Gli inserimenti sono molto veloci (oltre 500000 record in circa 2 minuti).

Ora sto cercando di utilizzare un database remoto su un server ospitato e ho notato che gli inserimenti sono molto molto lenti (meno di 500 record in circa 2 minuti). Questo significa 1000 volte più lento di localmente.

Se si tenta di inserire 500 record nel database remoto utilizzando SQL Server Management Studio l'operazione è completata in meno di 1 secondo.

Il problema è nell'applicazione client?

Qui la funzione di inserimento:

public void SetDemoDimCustomer() 
{ 
     DWContext dc = null; 

     try 
     { 
      dc = DWContext.Create(SqlServerInstance, DbName); 
      dc.Configuration.AutoDetectChangesEnabled = false; 

      dc.Database.ExecuteSqlCommand("DELETE FROM DimCustomer"); 
      dc.Database.ExecuteSqlCommand("DBCC CHECKIDENT ('DimCustomer', RESEED, 0)"); 

      DimCustomer objCustomer; 
      List<DimCustomer> lstDemoCustomers = new List<DimCustomer>(); 
      int length = 100; 

      for (int i = 0; i < length; i++) 
      { 
       objCustomer = new DimCustomer(); 
       objCustomer.Name = "Customer " + (i + 1); 
       objCustomer.CustomerBKey = (i + 1).ToString(); 

       lstDemoCustomers.Add(objCustomer); 
      } 

      dc.DimCustomer.AddRange(lstDemoCustomers); 
      dc.SaveChanges(); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
     finally 
     { 
      if (dc != null) 
      { 
       dc.Dispose(); 
      } 
     } 
    } 

Ho cercato di utilizzare Linq to SQL invece EF6 ma il risultato è lo stesso. Forse non è un problema specifico EF6.

Alcune informazioni riguardo il sistema remoto:

  • SO: Windows Server 2012
  • RDBMS: SQL Server 2014 Express Le

Grazie in anticipo.

aggiornamento dopo alcuni test con BULKINSERT

Ok qui i risultati dei miei primi test con BulkInsert:

  • 100 record -> EF6 AddRange: 9 sec./EF6 BulkInsert: 1 sec.
  • 1000 record -> EF6 AggiungiRange: 1:27 min./EF6 BulkInsert: 1 sec. (wow!)
  • 10000 record -> EF6 AddRange: 14:39 min./EF6 BulkInsert: 4 sec. (wooooow!)

Ora, naturalmente, il pacchetto EF6 BulkInsert è parte del mio progetto.

+0

Se questo è un codice una tantum che crea solo alcuni dati demo in il database, perché non basta scrivere una query per "INSERIRE" i record. Se questo codice corrisponde ai dati che si desidera creare, la query sarebbe banale da scrivere. –

+0

@JoshuaShearer questo è solo un metodo di prova che ho scritto per spiegare il problema. La vera procedura di inserimento è più complicata. Questo perché eviterei di scrivere query sql esplicite. La classe – jacktric

risposta

5

Sembra che la maggior parte del tempo trascorra sulla rete in attesa di un round trip da completare. EF non può essere inserito negli inserimenti batch (ancora). Quindi non puoi usare EF per gli inserti qui.

Indagare le soluzioni tipiche a questo problema (TVP e SqlBulkCopy).


Il modello di smaltimento in uso non è una buona scelta. È sufficiente avvolgere lo dc in "utilizzo" ed eliminare tutta la gestione delle eccezioni.

+0

[SqlBulkCopy] (https://msdn.microsoft.com/it-it/library/system.data.sqlclient.sqlbulkcopy (v = vs.110) .aspx) sembra essere molto interessante. Proverò a usarlo prima per guardare le tecniche di TVP. – jacktric

3

Come suggerito, SqlBulkCopy è la soluzione migliore, tuttavia non v'è un interessante pacchetto Nuget che fa BulkInsert per Entity Framework:

https://efbulkinsert.codeplex.com/

+0

Mille grazie per il tuo suggerimento. Proverò a utilizzare BulkInsert per Entity Framework e posterò un confronto con la mia strategia (cattiva) effettiva. – jacktric

+1

dare un'occhiata al mio primo confronto tra AddRange e BulkInsert. – jacktric

+0

Wow ... è impressionante – user2404597

Problemi correlati