#sql #sql-server #merge #sql-server-2017
#sql #sql-сервер #слияние #sql-server-2017
Вопрос:
Мне нужно объединить миллионы строк в таблицу. Целевая таблица имеет триггер ПОСЛЕ ОБНОВЛЕНИЯ. Весь процесс потребляет намного больше памяти, чем я хотел бы выделить, а база данных tempdb занимает место на диске.
Я бы хотел, чтобы команда СЛИЯНИЯ выполнялась партиями по 100 000 записей одновременно. Поскольку SET ROWCOUNT устарел, а курсоры неэффективны, я не уверен, каким будет наилучший подход для этого.
Комментарии:
1. Я не понимаю, как замена на
update
сmerge
изменит производительность триггера.
Ответ №1:
Подход, ориентированный на набор, был бы лучшим способом эффективного выполнения запроса. Итак, то, что вы делаете, кажется мне просто прекрасным. Если он использует временную базу данных и т. Д., Необходимо будет знать, выполняете ли вы какие-либо операции по строке за строкой, которые замедляются. Как правило, СЛИЯНИЕ представляет собой один оператор и, следовательно, является эффективным.
Другие вещи, которые следует учитывать, это то, что если у вас есть индексы в целевой таблице, вы можете удалить эти индексы, а затем запустить СЛИЯНИЕ с последующим воссозданием индексов.
Возвращаясь к вашему вопросу, вы можете разделить на пакеты, используя оператор mod и запустив СЛИЯНИЕ в цикле
например:
declare @i int
select @i=count(*)/10 from source
while @i>0
begin
merge
into dest d
using (select *
from source
where id%10000=i --here id is the primary key of the source table
) s
on d.id=s.id
when matched
set ...
when not matched
insert...
...rest of the insert/update logic here
set @i=@i-1
end
Ответ №2:
Попробуйте цикл WHILE
DECLARE @I INT = 1
WHILE (@I > 0)
BEGIN
;MERGE INTO Dst USING (
SELECT TOP 1000
FROM Src
WHERE NotUpdated
)
...
SET @I = @@ROWCOUNT
END
Комментарии:
1. чтобы не объединять одни и те же 1000 строк снова и снова, вы используете WHERE NotUpdated . Как бы вы реализовали это на Src, в середине слияния?
2. Это зависит от варианта использования. Вы можете присоединиться к таблице Dst, чтобы проверить, была ли обновлена строка. Преимущество этого решения заключается в том, что нет проблем с добавлением записей в Src или Dst во время цикла.
3. Это интересная идея. Вопрос: будет ли срабатывать триггер после выполнения каждой итерации цикла или (как я боюсь), только после выполнения всей транзакции?
4. Я протестировал это, и триггер запускается для каждой итерации цикла.