SqlBulkCopy Обработка ошибок / продолжить при ошибке - PullRequest
10 голосов
/ 17 июня 2009

Я пытаюсь вставить огромное количество данных на сервер SQL. Моя таблица назначения имеет уникальный индекс под названием «Хэш».

Я хотел бы заменить мою реализацию SqlDataAdapter на SqlBulkCopy. В SqlDataAapter есть свойство с именем «ContinueUpdateOnError», когда для него установлено значение true adapter.Update (таблица) вставит все возможные строки и пометит строки ошибок свойством RowError.

Вопрос в том, как использовать SqlBulkCopy для максимально быстрой вставки данных, отслеживая, какие строки были вставлены, а какие - нет (из-за уникального индекса)?

Вот дополнительная информация:

  1. Процесс итеративный, часто по расписанию повторяющийся.

  2. Исходная и целевая таблицы могут быть огромными, иногда миллионы строк.

  3. Несмотря на то, что сначала можно проверить значения хеш-функции, для каждой строки требуется две транзакции (сначала для выбора хеша из таблицы назначения, а затем для выполнения вставки). Я думаю, что в случае с adapter.update (table), проверка на RowError быстрее, чем проверка на хэш-хиты в строке.

Ответы [ 3 ]

7 голосов
/ 17 июня 2009

SqlBulkCopy, имеет очень ограниченные средства обработки ошибок, по умолчанию он даже не проверяет ограничения.

Тем не менее, это быстро, действительно очень быстро.

Если вы хотите обойти проблему дублирования ключа и определить, какие строки являются дубликатами в пакете. Один из вариантов:

  • start tran
  • Возьмите tablockx на таблицу, выберите все текущие значения "Hash" и добавьте их в HashSet.
  • Отфильтровать дубликаты и отчитаться.
  • Вставить данные
  • commit tran

Этот процесс будет работать эффективно, если вы вставляете огромные наборы, а размер исходных данных в таблице не слишком велик.

Не могли бы вы расширить свой вопрос, включив в него остальную часть проблемы.

EDIT

Теперь, когда у меня есть больше контекста, вот еще один способ сделать это:

  • Сделать массовую вставку во временную таблицу.
  • запуск сериализуемого тран
  • Выбрать все временные строки, которые уже находятся в таблице назначения ... сообщить о них
  • Вставьте данные из временной таблицы в реальную таблицу, выполнив левое соединение с хешем и включив все новые строки.
  • совершить транс

Этот процесс очень легок в поездках туда и обратно, и учитывая, что ваши спецификации должны быть очень быстрыми;

4 голосов
/ 10 июня 2014

Немного другой подход, чем уже предлагалось; Выполните SqlBulkCopy и поймайте SqlException брошенный:

    Violation of PRIMARY KEY constraint 'PK_MyPK'. Cannot insert duplicate 
key in object 'dbo.MyTable'. **The duplicate key value is (17)**.

Затем вы можете удалить все элементы из вашего источника из идентификатора 17, первой дублированной записи. Здесь я делаю предположения, которые относятся к моим обстоятельствам и, возможно, не к вашим; то есть, что дублирование вызвано точными теми же данными из ранее неудачного SqlBulkCopy из-за ошибок SQL / Network во время загрузки.

1 голос
/ 18 июня 2009

Примечание: это резюме ответа Сэма с чуть более подробной информацией

Спасибо Сэму за ответ. Я поместил его в ответ из-за нехватки комментария.

Исходя из вашего ответа, я вижу два возможных подхода:

Решение 1:

  • start tran
  • захватить все возможные значения хеша попадания, выполнив команду «выбрать хеш в целевой таблице, где хэш (val1, val2, ...)
  • отфильтровывать дубликаты и сообщать
  • вставить данные
  • commit tran

решение 2:

  • Создать временную таблицу для отражения схема таблицы назначения
  • массовая вставка в временную таблицу
  • запуск сериализуемой транзакции
  • Получить повторяющиеся строки: "выберите хеш из где можно tempTable.hash = destinationTable.hash "
  • отчет о повторяющихся строках
  • Вставить данные во временную таблицу в таблицу адресатов: «выберите * into destinationTable из временного левого соединения temptable.hash = destinationTable.hash, где destinationTable.hash равно нулю»
  • совершить транс

Поскольку у нас есть два подхода, то какой подход наиболее оптимизирован? Оба подхода должны извлекать дубликаты строк и составлять отчет, в то время как второй подход требует дополнительного:

  • создание и удаление временных таблиц
  • еще одна команда sql для перемещения данных из временной таблицы в таблицу назначения
  • зависит от процента коллизий хэшей, он также передает много ненужных данных по сети

Если это единственные решения, мне кажется, что победит первый подход. Что, вы парни, думаете? Спасибо!

...