2010-11-18 7 views
2

Travailler avec MYSQL en C#:Batching ensemble des commandes paramétrées dans MYSQL

J'ai une collection de IDbCommands paramétrées Je voudrais exécuter. Le sont un mélange des mises à jour, insertions et suppressions, en ce moment je fais:


using (IDbConnection connection = Connecter.CreateConnection()) 
{ 
    foreach(IDBCommand command in m_commands) 
    { 
    command.Connection = connection; 
    command.ExecuteNonQuery(); 
    } 
} 

Les commandes utilisent beaucoup de paramètres, donc je ne peux pas combiner les textes de commande de chaque commande ensemble. La performance est assez terrible, et je sais qu'il doit y avoir un meilleur moyen. L'utilisation de la mise à jour MYSql Bulk serait acceptable, mais je ne vois pas comment traduire les valeurs des paramètres dans le fichier sans risquer des attaques par injection SQL.

Quelqu'un a des suggestions?

(je l'ai attaché mettre toutes les commandes à l'intérieur d'une transaction qui aide un peu, mais pas assez)

Répondre

1

Si plusieurs insertions/modifications/suppressions sont à appliquer à la même table (s), pensez à utiliser une combinaison MySqlDataAdapter/DataTable pour regrouper des instructions similaires. La définition de la propriété UpdateBatchSize de MySqlDataAdapter activera/désactivera le traitement par lots. Ainsi, les insertions/mises à jour/suppressions sur la même table peuvent être envoyées à la BD en un seul passage.

Je l'ai fait l'OracleDataAdapter et SqlDataAdapter avec des gains de performance significatifs. MySqlDataAdapter semble également implémenter le batching de base (mais pas testé). Une suggestion serait de créer votre propre classe wrapper qui cache les classes DbDataAdapter/DataTable sous-jacentes dans une forme de classe DbCommandBatch. Cette classe peut ensuite générer la sauvegarde DataTable requise à partir d'un modèle IDbCommand et, finalement, regrouper des commandes similaires si vous le souhaitez.

public interface IDbBatchCommandFactory 
{ 
    IDbCommandBatch Create(IDbCommand templateCommand); 
} 

Ainsi, la méthode Create pourrait réellement construire le DataTable nécessaire à partir d'une commande de modèle si on le souhaite (peut faciliter la vie en fonction de ce code que vous avez déjà) par itérer sur la collection de paramètres existant. Cela pourrait alors créer une classe qui implémente une interface quelque chose comme:

public interface IDbBatchCommand : IDisposable 
{ 
    void AddToBatch(ParameterCollection parameters); 
    void ExecuteBatch(IDbTransaction transaction); 
} 

Si cela est sur la bonne voie pour ce que vous avez besoin, je peux fournir un exemple de code. Si chaque commande est distincte l'une de l'autre (c'est-à-dire, des tables toujours différentes, etc.), cela ne fournira aucune valeur.

Note: Dans un monde parfait, des classes comme SqlCommandSet etc seraient publiquement disponibles pour éviter d'avoir à faire ce fouillis.

+0

Merci, en utilisant un DataTable était le chemin à parcourir. –

0

Je n'ai pas beaucoup d'expérience en utilisant MySQL, donc je ne suis pas familier avec la fonctionnalité de mise à jour en bloc que a. Cela semble prometteur pour ce que vous aimeriez faire, mais je vois votre inquiétude s'il est nécessaire que vous enregistriez d'abord les données dans un fichier avant d'utiliser Bulk Update.

Je ne suis pas sûr si MySQL a quelque chose de similaire à cela, mais ADO.NET provides a SqlBulkCopy command qui fonctionne avec SQL Server. Cela vous permet essentiellement d'insérer des données dans la base de données directement à partir d'un lecteur de données fourni par votre code, évitant ainsi la nécessité de créer un fichier et évitant ainsi de devoir vous soucier des problèmes liés aux chaînes.

MySQL 4.1 has prepared statements. Ces commandes sont-elles toutes identiques à l'exception des valeurs des paramètres? Je me demande si vous verriez de meilleures performances si vous avez essayé de tirer profit de la méthode IDbCommand.Prepare:

 using (IDbConnection connection = Connector.CreateConnection()) 
     { 
      var command = connection.CreateCommand(); 

      command.CommandText = "<command text>"; 

      var paramA = command.CreateParameter(); 
      paramA.ParameterName = "ParameterA"; 
      paramA.DbType = DbType.Int32; 
      command.Parameters.Add(paramA); 

      var paramB = command.CreateParameter(); 
      paramB.ParameterName = "ParameterB"; 
      paramB.DbType = DbType.String; 
      command.Parameters.Add(paramB); 

      var paramC = command.CreateParameter(); 
      paramC.ParameterName = "ParameterC"; 
      paramC.DbType = DbType.Decimal; 
      command.Parameters.Add(paramC); 

      command.Prepare(); 

      foreach (ProcedureArgs args in m_procedureArgs) 
      { 
       paramA.Value = args.ParamA; 
       paramB.Value = args.ParamB; 
       paramC.Value = args.ParamC; 
       command.ExecuteNonQuery(); 
      } 
     } 
Questions connexes