web-dev-qa-db-fra.com

Copier en bloc un DataTable dans MySQL (similaire à System.Data.SqlClient.SqlBulkCopy)

Je migre mon programme de Microsoft SQL Server vers MySQL. Tout fonctionne bien sauf un problème avec la copie en bloc.

Dans la solution avec MS SQL, le code ressemble à ceci:

connection.Open();
SqlBulkCopy bulkCopy = new SqlBulkCopy(connection);
bulkCopy.DestinationTableName = "testTable";
bulkCopy.WriteToServer(rawData);

Maintenant, j'essaie de faire quelque chose de similaire pour MySQL. Parce que je pense qu'il y aurait de mauvaises performances, je ne veux pas écrire le DataTable dans un fichier CSV et faire l'insertion à partir de là avec la classe MySqlBulkLoader.

Toute aide serait très appréciée.

11
Michael Schegg

Parce que je pense qu'il y aurait de mauvaises performances, je ne veux pas écrire le DataTable dans un fichier CSV et faire l'insertion à partir de là avec la classe MySqlBulkLoader.

Ne pas exclure une solution possible basée sur des hypothèses non fondées. Je viens de tester l'insertion de 100 000 lignes d'un System.Data.DataTable dans une table MySQL en utilisant un MySqlDataAdapter#Update() standard dans une Transaction. Il a toujours fallu environ 30 secondes pour exécuter:

using (MySqlTransaction tran = conn.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
    using (MySqlCommand cmd = new MySqlCommand())
    {
        cmd.Connection = conn;
        cmd.Transaction = tran;
        cmd.CommandText = "SELECT * FROM testtable";
        using (MySqlDataAdapter da = new MySqlDataAdapter(cmd))
        {
            da.UpdateBatchSize = 1000;
            using (MySqlCommandBuilder cb = new MySqlCommandBuilder(da))
            {
                da.Update(rawData);
                tran.Commit();
            }
        }
    }
}

(J'ai essayé différentes valeurs pour UpdateBatchSize, mais elles ne semblent pas avoir d'impact significatif sur le temps écoulé.)

En revanche, le code suivant utilisant MySqlBulkLoader n'a pris que 5 ou 6 secondes pour s'exécuter ...

string tempCsvFileSpec = @"C:\Users\Gord\Desktop\dump.csv";
using (StreamWriter writer = new StreamWriter(tempCsvFileSpec))
{
    Rfc4180Writer.WriteDataTable(rawData, writer, false);
}
var msbl = new MySqlBulkLoader(conn);
msbl.TableName = "testtable";
msbl.FileName = tempCsvFileSpec;
msbl.FieldTerminator = ",";
msbl.FieldQuotationCharacter = '"';
msbl.Load();
System.IO.File.Delete(tempCsvFileSpec);

... y compris le temps nécessaire pour vider les 100 000 lignes du DataTable dans un fichier CSV temporaire (avec un code similaire à this ), le chargement en bloc à partir de ce fichier et la suppression ultérieure du fichier.

12
Gord Thompson

En utilisant n'importe quel paquetage BulkOperation NuGet, vous pouvez facilement le faire.

Voici un exemple utilisant le paquet de https://www.nuget.org/packages/Z.BulkOperations/2.14.3/

using Z.BulkOperations;

......

MySqlConnection conn = DbConnection.OpenConnection();
DataTable dt = new DataTable("testtable");
MySqlDataAdapter da = new MySqlDataAdapter("SELECT * FROM testtable", conn);
MySqlCommandBuilder cb = new MySqlCommandBuilder(da);
da.Fill(dt);

à la place d'utiliser 

......
da.UpdateBatchSize = 1000;
......
da.Update(dt)

juste suivre deux lignes 

var bulk = new BulkOperation(conn);
bulk.BulkInsert(dt);

il ne faudra que 5 secondes pour copier l'intégralité du DataTable dans MySQL sans d'abord vider les 100 000 lignes du DataTable dans un fichier CSV temporaire. 

0
alex