Массовая копия DataTable в MySQL (аналогично System.Data.SqlClient.SqlBulkCopy)

Я переношу свою программу с Microsoft SQL Server на MySQL. Все работает хорошо, кроме одной проблемы с массовой копией.

В решении с MS SQL код выглядит следующим образом:

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

Теперь я пытаюсь сделать что-то подобное для MySQL. Поскольку я думаю, что будет плохая производительность, я не хочу записывать DataTable в CSV файл и делать там вставку с классом MySqlBulkLoader.

Любая помощь будет высоко оценена.

Ответ 1

Поскольку я думаю, что будет плохая производительность, я не хочу писать DataTable в CSV файл и делать туда вставку с классом MySqlBulkLoader.

Не исключайте возможное решение, основанное на необоснованных предположениях. Я только что протестировал вставку из 100 000 строк из таблицы System.Data.DataTable в таблицу MySQL, используя стандартный MySqlDataAdapter#Update() внутри a Transaction. Для его выполнения потребовалось около 30 секунд:

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();
            }
        }
    }
}

(Я попробовал несколько разных значений для UpdateBatchSize, но они не оказали существенного влияния на прошедшее время.)

В отличие от этого, следующий код с использованием MySqlBulkLoader занял всего 5 или 6 секунд...

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);

... включая время сброса 100 000 строк из DataTable во временный CSV файл (используя код, похожий на этот), объемный - загрузка из этого файла и последующее удаление файла.

Ответ 2

Используя любой пакет BulkOperation NuGet, вы можете легко это сделать.

Ниже приведен пример использования пакета с 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);

Вместо того, чтобы использовать

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

просто следуя двум строкам

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

займет всего 5 секунд, чтобы скопировать весь DataTable в MySQL без предварительного сброса 100 000 строк из DataTable во временный файл CSV.