10 votes

Moyen le plus rapide pour mettre à jour (peupler) 1 000 000 enregistrements dans une base de données à l'aide de .NET

Je utilise ce code pour insérer 1 million d'enregistrements dans une table vide dans la base de données. Bon, sans beaucoup de code je vais commencer du point où j'ai déjà interagi avec les données, et lu le schéma dans un DataTable:

Alors:

DataTable returnedDtViaLocalDbV11 = DtSqlLocalDb.GetDtViaConName(strConnName, queryStr, strReturnedDtName);

Et maintenant que nous avons returnedDtViaLocalDbV11 créons un nouveau DataTable qui soit un clone de la table de base de données source:

DataTable NewDtForBlkInsert = returnedDtViaLocalDbV11.Clone();

Stopwatch SwSqlMdfLocalDb11 = Stopwatch.StartNew();
NewDtForBlkInsert.BeginLoadData();

for (int i = 0; i < 1000000; i++)
{
   NewDtForBlkInsert.LoadDataRow(new object[] { null, "NewShipperCompanyName"+i.ToString(), "NewShipperPhone" }, false);
}
NewDtForBlkInsert.EndLoadData();

DBRCL_SET.UpdateDBWithNewDtUsingSQLBulkCopy(NewDtForBlkInsert, tblClients._TblName, strConnName);

SwSqlMdfLocalDb11.Stop();

var ResSqlMdfLocalDbv11_0 = SwSqlMdfLocalDb11.ElapsedMilliseconds;

Ce code alimente 1 million d'enregistrements dans une base de données SQL embarquée (localDb) en 5200ms. Le reste du code implémente juste le bulkCopy mais je le posterai quand même.

 public string UpdateDBWithNewDtUsingSQLBulkCopy(DataTable TheLocalDtToPush, string TheOnlineSQLTableName, string WebConfigConName)
 {
    //Ouvrir une connexion à la base de données. 
    using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings[WebConfigConName].ConnectionString))
    {
       connection.Open();

       // Effectuer un décompte initial sur la table de destination.
       SqlCommand commandRowCount = new SqlCommand("SELECT COUNT(*) FROM "+TheOnlineSQLTableName +";", connection);
       long countStart = System.Convert.ToInt32(commandRowCount.ExecuteScalar());

       var nl = "\r\n";
       string retStrReport = "";
       retStrReport = string.Concat(string.Format("Nombre de départs = {0}", countStart), nl);
       retStrReport += string.Concat("==================================================", nl);
       // Créer une table avec quelques lignes. 
       //DataTable newCustomers = TheLocalDtToPush;

       // Créer l'objet SqlBulkCopy.  
       // Remarquez que les positions de colonne dans le DataTable source  
       // correspondent aux positions de colonne dans la table de destination donc  
       // pas besoin de mapper les colonnes.  
       using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
       {
          bulkCopy.DestinationTableName = TheOnlineSQLTableName;

          try
          {
             // Écrire depuis la source vers la destination.
             for (int colIndex = 0; colIndex < TheLocalDtToPush.Columns.Count; colIndex++)
             {
                bulkCopy.ColumnMappings.Add(colIndex, colIndex);
             }
             bulkCopy.WriteToServer(TheLocalDtToPush);
          }

          catch (Exception ex)
          {
             Console.WriteLine(ex.Message);
          }
       }

       // Effectuer un décompte final sur la destination  
       // table pour voir combien de lignes ont été ajoutées. 
       long countEnd = System.Convert.ToInt32(
       commandRowCount.ExecuteScalar());

       retStrReport += string.Concat("Fin de décompte = ", countEnd, nl);
       retStrReport += string.Concat("==================================================", nl);
       retStrReport += string.Concat((countEnd - countStart)," lignes ont été ajoutées.", nl);
       retStrReport += string.Concat("Nouveaux Clients a été mis à jour avec succès", nl, "FIN DU PROCESS !");
       //Console.ReadLine();
       return retStrReport;
   }
}

Essayer via une connexion à un serveur SQL était environ 7000ms (au mieux) & en moyenne ~7700ms. Aussi via une base de données NoSQL kv aléatoire a pris environ 40 secondes (vraiment je n'ai même pas gardé les enregistrements car il a dépassé le x2 des variantes sql). Alors... y a-t-il un moyen plus rapide que ce que j'ai testé dans mon code?

Modifier

je utilise Win7 x64 8 Go de RAM et ce qui est le plus essentiel je pense (comme i5 3GHz) n'est pas si génial maintenant Le x3 500 Go Wd sur Raid-0 fait encore mieux le travail mais je dis simplement si vous le vérifiez sur votre pc bien sûr comparez-le à toute autre méthode dans votre configuration

2voto

Mike Henderson Points 992

Avez-vous essayé SSIS? Je n'ai jamais écrit de package SSIS avec une connexion loacldb, mais c'est le genre d'activité pour laquelle SSIS convient bien.

Si votre source de données est un serveur SQL, une autre idée serait de mettre en place un serveur lié. Je ne suis pas sûr que cela fonctionnerait avec localdb. Si vous pouvez configurer un serveur lié, vous pourriez contourner complètement le C# et charger vos données avec une instruction SQL INSERT .. SELECT ... FROM ...

1voto

anees Points 210

Vous pouvez utiliser Dapper.NET. Dapper est un micro-ORM, exécute une requête et mappe les résultats vers une liste fortement typée. La correspondance relationnelle objet (ORM, O/RM et O/R mapping) dans les logiciels informatiques est une technique de programmation pour convertir des données entre des systèmes de types incompatibles dans les langages de programmation orientés objet. Cela crée, en effet, une "base de données objet virtuelle" qui peut être utilisée à partir du langage de programmation

Pour plus d'informations :

consultez https://code.google.com/p/dapper-dot-net/

Dépôt GitHub : https://github.com/SamSaffron/dapper-dot-net J'espère que cela vous aide..

1voto

Jayrwafu Points 11

Supprimez la boucle... En SQL, essayez de créer une table avec 1 million de lignes... et utilisez left join pour insérer/sélectionner des données

0voto

eglasius Points 26221

Essayez de l'envoyer sans le stocker dans une table de données.

Voir l'exemple à la fin de ce post, qui vous permet de le faire avec un énumérateur http://www.developerfusion.com/article/122498/using-sqlbulkcopy-for-high-performance-inserts/

0voto

Si vous créez simplement des données sans signification, créez une procédure stockée et appelez-la simplement via .net

Si vous passez de vraies données, les passer à une procédure stockée serait plus rapide mais il serait préférable de supprimer la table et de la recréer avec les données.

Si vous insérez une ligne à la fois, cela prendra plus de temps que de tout insérer en une seule fois. Cela prendra encore plus de temps si vous devez écrire des index.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X