SqlBulkCopy с логикой повторения
У меня была проблема с вставкой большого набора записей в таблицу сервера Sql. Я решаю эту проблему с помощью SqlBulkCopy. Теперь я могу вставить запись довольно быстро.
У меня есть вопрос, что если какая-либо транзакция не удалась при вставке записей, я должен повторить ту же операцию 3 раза. Как мы можем добиться логики повторов с SqlBulkCopy?
using (var connection = DatabaseOperations.CreateConnection(ConnectString))
{
connection.Open();
var transaction = connection.BeginTransaction();
try
{
var dt = new DataTable();
dt.Columns.Add("EmployeeID");
dt.Columns.Add("Name");
for (var i = 1; i < 1000000; i++)
dt.Rows.Add(i + 1, "Name " + i + 1);
using (var sqlBulk = new SqlBulkCopy(connection,SqlBulkCopyOptions.Default, transaction as SqlTransaction))
{
sqlBulk.DestinationTableName = "Employees";
sqlBulk.BatchSize = 100000;
sqlBulk.WriteToServer(dt);
}
}
catch (SqlException ex)
{
transaction.Rollback();
throw new CustomException("SQL Exception", ex);
}
catch (Exception e)
{
transaction.Rollback();
throw;
}
transaction.Commit();
}
1 ответ
Вот совет: НЕ выполняйте SqlBulkCopy в целевой таблице. Вот так просто.
Мне потребовался день, чтобы решить эту проблему.
- Получить схему целевой таблицы (что просто сделать с помощью INFORMATION_SCHEMA)
- Создайте временную таблицу с такими же полями.
- Вставить во временную таблицу
- Затем используйте INSERT INTO SELECT FROM, чтобы скопировать данные.
Весь механизм блокировки SqlBulkCopy сломан и не подлежит ремонту. Он получает эксклюзивную блокировку таблицы. Что может не понадобиться, но хорошо.
Проблема в том, что он пытается получить его БЕЗ ОЖИДАНИЯ - любая блокировка любой строки блокирует это. Он повторяет X раз, затем сдается. На загруженном столе это никогда (или редко) сработает.
Да, и он сохраняет эту блокировку во время загрузки, что обычно медленнее, чем моя вставка решения.
Мой подход решает эту проблему. Вы всегда можете заблокировать свою временную таблицу. Затем вставка в ждет своей очереди. И копирование происходит быстрее, чем загрузка по сети.
Да, и вам НЕ нужна DataTable - вы можете легко запрограммировать свой собственный источник таблицы объектов, используя отражение (пару часов). DataTAble требует много памяти.