#sql-server-2005 #triggers
#sql-server-2005 #триггеры
Вопрос:
У нас есть триггер, который создает записи аудита для таблицы и соединяет таблицы inserted
и deleted
, чтобы увидеть, изменились ли какие-либо столбцы. Соединение хорошо работает для небольших наборов, но теперь я обновляю около 1 миллиона строк, и оно не завершается через несколько дней. Я попытался обновить выбранное количество строк с разными порядками величины, и очевидно, что это экспоненциально, что имело бы смысл, если inserted
/ deleted
tables сканируются для выполнения соединения.
Я попытался создать индекс, но получил сообщение об ошибке: Cannot find the object "inserted" because it does not exist or you do not have permissions.
Есть ли какой-нибудь способ ускорить это?
Комментарии:
1. Я просто подумал о выборе каждого из них в новые временные таблицы, после чего я смогу создавать индексы. Тем не менее, я также обеспокоен производительностью отдельных записей, и это кажется излишним для них.
2. @Martin — Сейчас 2005 год, и я только что обновил тег, чтобы отразить это.
Ответ №1:
Вставка во временные таблицы, индексируемые в столбцах объединения, может улучшить ситуацию, поскольку inserted
и deleted
не индексируются.
Вы можете проверить @@ROWCOUNT
внутри триггера, чтобы выполнять эту логику только выше некоторого порогового количества строк, хотя на SQL Server 2008 это может несколько завышать число, если триггер был запущен в результате выполнения MERGE
инструкции (он вернет общее количество строк, затронутых всеми MERGE
действиями, а не только относящимся к этомуконкретный триггер).
В этом случае вы можете просто сделать что-то вроде SELECT @NumRows = COUNT(*) FROM (SELECT TOP 10 * FROM INSERTED) T
проверки, соблюден ли порог.
Добавление
Еще одна возможность, с которой вы могли бы поэкспериментировать, — это просто обойти триггер для этих больших обновлений. Вы могли SET CONTEXT_INFO
бы установить флаг и проверить значение этого внутри триггера. Затем вы можете использовать OUTPUT inserted.*, deleted.*
для получения значений «до» и «после» для строки без необходимости JOIN
вообще.
DECLARE @TriggerFlag varbinary(128)
SET @TriggerFlag = CAST('Disabled' AS varbinary(128))
SET CONTEXT_INFO @TriggerFlag
UPDATE YourTable
SET Bar = 'X'
OUTPUT inserted.*, deleted.* INTO @T
/*Reset the flag*/
SET CONTEXT_INFO 0x
Комментарии:
1. Отличный момент для установки порога. Это может сделать триггер довольно сложным, но я полагаю, что есть компромиссы с чем угодно. Я все еще озадачен одним: у нас есть другая база данных, которая почти идентична, и она не испытывает такого замедления. Таблицы, триггеры и индексы кажутся идентичными, хотя я еще не проводил подробного сравнения.