Сначала о процессе обновления.Я понимаю, ваша процедура просто вызывает себя, когда дело доходит до обновления следующей строки.С 300К строк это, конечно, не будет очень быстрым, даже без регистрации (хотя, скорее всего, это займет гораздо меньше дней).Но что меня совершенно не устраивает, так это то, как можно обновлять более 32 строк таким образом, не достигая максимального уровня вложенности.Возможно, у меня неправильная последовательность действий.
В любом случае, я бы сделал это по-другому, используя всего одну инструкцию:
UPDATE yourtable
SET @value = Value = CASE ID
WHEN @id THEN @value
ELSE @value / 2 /* basically, your formula */
END
WHERE ID >= @id
OPTION (MAXDOP 1);
Бит OPTION (MAXDOP 1)
оператора ограничиваетстепень параллелизма для оператора до 1, таким образом, гарантируя, что строки обновляются последовательно, и каждое значение основывается на предыдущем, то есть на значении в строке с предыдущим значением идентификатора.Кроме того, для столбца ID
следует сделать кластеризованный индекс, которым он обычно является по умолчанию, если он стал первичным ключом.
Другие функции процедуры обновления, т. Е. Удаление и повторное создание триггера, должнывероятно, будет заменено отключением и повторным включением it:
ALTER TABLE yourtable DISABLE TRIGGER yourtabletrigger
/* the update part */
ALTER TABLE yourtable ENABLE TRIGGER yourtabletrigger
Но тогда вы говорите, что триггер не должен быть на самом деле удален / отключен, потому что несколько пользователей могут обновить таблицув то же время.
Хорошо, тогда мы не касаемся триггера.
Вместо этого я бы предложил добавить в таблицу специальный столбец, о котором пользователи не должны знатьили, по крайней мере, не должно заботиться о многом и должно быть как-то сделано, чтобы никогда не трогать.Этот столбец должен обновляться только процессом «каскадного обновления».Проверяя, обновлялся ли этот столбец или нет, вы узнаете, следует ли вам вызывать процедуру обновления и ведения журнала.
Итак, в вашем триггере может быть что-то вроде этого:
IF NOT UPDATE(SpecialColumn) BEGIN
/* assuming that without SpecialColumn only one row can be updated */
SELECT TOP 1 @id = ID, @value = Value FROM inserted;
EXEC UpdateProc @id, @value;
EXEC LogProc ...;
END
В UpdateProc
:
UPDATE yourtable
SET @value = Value = @value / 2,
SpecialColumn = SpecialColumn /* basically, just anything, since it can
only be updated by this procedure */
WHERE ID > @id
OPTION (MAXDOP 1);
Возможно, вы заметили, что оператор UPDATE на этот раз немного отличается.Я понимаю, что ваш триггер FOR UPDATE (= AFTER UPDATE), это означает, что строка @id уже будет обновлена пользователем.Таким образом, процедура должна пропустить ее и начать со следующей строки, а выражение обновления теперь может быть просто формулой.
В заключение я хотел бы сказать, что мое тестовое обновление включало 299 995 из 300 000 строк моей таблицы.и заняло примерно 3 секунды на моей не очень быстрой системе.Без регистрации, конечно, но я думаю, что это должно дать вам основную картину того, как быстро это может быть.