Любой способ вставки или обновления SQLBulkCopy, если он существует?

Мне нужно периодически обновлять очень большую таблицу, и SQLBulkCopy идеально подходит для этого, только у меня есть индекс с двумя столбцами, который предотвращает дублирование. Есть ли способ использовать SQLBulkCopy как «вставить или обновить, если существует»?

Если нет, то как это сделать наиболее эффективно? Опять же, я говорю о таблице с миллионами записей.

Спасибо


person Sol    schedule 03.02.2011    source источник


Ответы (6)


Я бы загрузил данные во временную промежуточную таблицу, а затем сделал бы upsert в итоговую таблицу. См. здесь для примера выполнения апсерта.

person btilly    schedule 03.02.2011
comment
Я не слишком хорошо знаком со службами SSIS, как именно они помогут выполнить эту задачу? - person Sol; 03.02.2011
comment
Это очень дорогой бизнес. Создание временной таблицы и последующее слияние. - person Alex M; 17.11.2020

Я опубликовал пакет nuget (SqlBulkTools) для решения этой проблемы.

Вот пример кода, который позволяет выполнить массовое обновление.

var bulk = new BulkOperations();
var books = GetBooks();

using (TransactionScope trans = new TransactionScope())
{
    using (SqlConnection conn = new SqlConnection(ConfigurationManager
    .ConnectionStrings["SqlBulkToolsTest"].ConnectionString))
    {
        bulk.Setup<Book>()
            .ForCollection(books)
            .WithTable("Books")
            .AddAllColumns()
            .BulkInsertOrUpdate()
            .MatchTargetOn(x => x.ISBN)
            .Commit(conn);
    }

    trans.Complete();
}

Для очень больших таблиц есть опции для добавления блокировок таблиц и временного отключения некластеризованных индексов. Дополнительные примеры см. В документации SqlBulkTools.

person Greg R Taylor    schedule 13.09.2016
comment
Я должен сказать, что эта библиотека полна добра. Мне пришлось написать службу Windows, которая выполняла некоторую работу с ETL, и взаимодействия с базой данных было недостаточно, чтобы оправдать даже MicroORM, и эта библиотека SqlBulkTools была идеальной. Спасибо!. Хорошо сделано! - person Hallmanac; 20.04.2017
comment
Ссылка на документацию мертва (404). - person Gord Thompson; 11.05.2017
comment
SqlBulkTools был продан ZZZ Projects. - person Greg R Taylor; 12.05.2017
comment
Сейчас 2020 год, и я использую этот пакет. Производительность отличная, и это именно то, что мне нужно для массовой вставки или обновления! - person Rob L; 24.04.2020
comment
Также отлично работает, есть ли идея использовать CancellationToken для аварийного восстановления частичной операции (поскольку они, вероятно, будут очень долгими)? - person morleyc; 11.07.2020

Не за один шаг, но в SQL Server 2008 вы могли:

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

Подробнее об заявлении MERGE

person marc_s    schedule 03.02.2011

Вместо создания новой временной таблицы, которая, кстати, занимает больше места и памяти.

Я создал триггер с INSTEAD OF INSERT и использую внутри оператора MERGE.

Но не забудьте добавить параметр SqlBulkCopyOptions.FireTriggers в SqlBulkCopy.

Это мои два цента.

person Ivan Paniagua    schedule 06.11.2013

Другой альтернативой было бы не использовать временную таблицу, а использовать хранимую процедуру с параметром, имеющим табличное значение. Передайте объекту данных объекту sp и выполните слияние там.

person jb5253    schedule 21.02.2013

Получил подсказку от @Ivan. Для тех, кому может понадобиться, вот что я сделал.

create trigger yourschma.Tr_your_triger_name
    on yourschma.yourtable
    instead of INSERT
    as
    merge into yourschma.yourtable as target
    using inserted as source
    on (target.yourtableID = source.yourtableID)
    when matched then
        update
        set target.ID     = source.ID,
            target.some_column = source.some_column,
            target.Amount                       = source.Amount
    when not matched by target then
        insert (some_column, Amount)
        values (source.some_column, source.Amount);
go
person Shengfeng Li    schedule 02.11.2019