Разделить обновление на партии (мелкие кусочки, проходя по всему набору). Хотя это звучит вопреки обычному совету базы данных «не зацикливайся, используй наборы», на самом деле это не так: вы просто используете меньшие наборы, а не зацикливаетесь на уровне строк. Лучший способ пакетного обновления, подобного этому, - «пройтись по кластерному индексу». Я не уверен, имеет ли этот термин смысл в СУБД, которую вы используете, но, по сути, это означает, что вы выбираете фрагменты, которые вы обновляете в каждом цикле, на основе порядка, в котором они будут найдены в обновляемом объекте таблицы. PK_ID звучит так, как будто он является кандидатом для использования, но если необработанные данные таблицы не упорядочены в этом столбце, это станет более сложным. В T-SQL пакетный цикл может выглядеть так:
DECLARE
@ID int,
@Count int
SET @ID = 1
SET @Count = 1
WHILE @Count > 0 BEGIN
UPDATE N
SET N.2ND_ID = O.2ND_ID
FROM
NEW_TABLE AS N
INNER JOIN OLD_TABLE AS O ON N.PK_ID = O.PK_ID
WHERE
N.2ND_ID <> O.2ND_ID
AND N.3RD_ID IS NOT NULL
AND O.3RD_ID IS NULL
AND N.CODE IS NOT NULL
AND O.CODE IS NULL
AND N.PK_ID BETWEEN @ID AND @ID + 4999
SET @Count = @@RowCount
SET @ID = @ID + 5000
END
В этом примере предполагается, что ваш столбец PK_ID плотно упакован, что каждое обновление будет по-настоящему достигать 5000 строк. Если это не так, переключитесь на метод с использованием TOP 5000 и либо выведите обновленные PK_ID в таблицу, либо найдите @StartID и @EndID для следующего обновления за один шаг, а затем выполните его.
По моему опыту, хорошие размеры партий составляют от 1000 до 20000 рядов. На сервере MS-SQL предпочтительным местом, как представляется, является чуть меньше числа, которое вынуждает переключиться с поиска на сканирование (потому что в конечном итоге механизм обработки БД предполагает, что одно сканирование дешевле, чем множество поисков, хотя это часто бывает неправильно при работе с таблицами из 5 миллионов строк).
Выберите идентификаторы и данные для обновления в рабочую / временную таблицу, а затем присоединитесь к ней. Идея состоит в том, чтобы выполнить простое сканирование с помощью простого оператора INSERT, затем добавить индексы во временную таблицу и выполнить обновление, не прибегая к сложному предложению WHERE. Как только таблица содержит только строки, которые нужно обновить, и необходимые столбцы, предложение WHERE не только может потерять большинство своих условий, но временная таблица имеет намного меньше строк и намного больше строк на странице (поскольку в ней нет лишних столбцов), что значительно улучшит производительность. Это может быть сделано даже на этапах, когда создается «тень» новой таблицы, затем «тень» старой таблицы, затем соединение между ними и, наконец, соединение к новой таблице для ее обновления. Хотя это звучит как большая работа, я думаю, вы будете удивлены совершенно безумной скоростью завершения, которую это может предложить.