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 требует много памяти.

Другие вопросы по тегам