Я пытался решить проблему медленного триггера, и теперь, когда я прошел методом проб и ошибок, я все еще не знаю, в чем была первоначальная проблема.
Запрос, который я выполняю, - этоследующее:
UPDATE tblA
SET X = NULL
WHERE X IS NOT NULL AND Z = 0
Обновляется около 30 тыс. строк.
И часть триггера AFTER INSERT, UPDATE на tblA, вызывающая проблему, была следующей:
IF EXISTS(SELECT 1
FROM inserted
LEFT JOIN deleted ON deleted.PK = inserted.PK
WHERE (inserted.Y IS NOT NULL AND deleted.Y IS NULL)
OR inserted.Y <> deleted.Y
BEGIN
-- The above condition is not met for my query so we would never get here
INSERT INTO tblB
(...)
SELECT
inserted.X,
...
FROM
inserted
LEFT JOIN deleted ON deleted.PK = inserted.PK
WHERE (inserted.Y IS NOT NULL AND deleted.Y IS NULL)
OR inserted.Y <> deleted.Y
END
Я полагаю, что вышеупомянутое IF EXISTS было включено, чтобы остановить потенциальные циклические срабатывания триггеров INSERT, когда вставки фактически не происходили, но на самом деле это не проблема для tblB, так как он имеет только один триггер.
Поэтому я изменил это на следующее:
INSERT INTO tblB
(...)
SELECT
inserted.X,
...
FROM
inserted
LEFT JOIN deleted ON deleted.PK = inserted.PK
WHERE (inserted.Y IS NOT NULL AND deleted.Y IS NULL)
OR inserted.Y <> deleted.Y
И время запроса на обновление теперь сократилось с> 1 часа до приблизительно 30 секунд.
Я ожидал, что онозаймет столько же времени.Почему это быстрее?
ОБНОВЛЕНИЕ: После проверки плана выполнения для выполнения моего запроса на обновление с медленным триггером
Проверка IF EXISTS обошлась в 0%, с73% стоимости идет на утверждение другого триггера, который вносит изменения в таблицу аудита.Само по себе это не кажется необоснованным, поскольку это утверждение довольно сложное с большим количеством объединений, но я не знаю, почему мое изменение в переписывании IF EXISTS имело какое-либо значение.Возможно, моя проверка IF EXISTS как-то мешает вставке таблицы аудита, чтобы замедлить их, но я не знаю, почему новая версия не делает то же самое, поскольку содержит тот же SELECT.[Большая часть этой стоимости была потрачена на буферизацию таблицы.]
Еще 13% стоимости запроса тратится на третий триггер, который обновляет временную метку на tblA, если конкретные значения столбца изменились.Это снова включается при вставке и удалении, плюс по табличке.Этот оператор обновления не оказал бы никакого влияния на мой запрос, так как изменения в столбце X не заслуживают обновления отметки времени.[Эта стоимость была разделена между внутренним объединением хеш-соответствия между tblA и вставленным, и обновлением кластеризованного индекса - кажется разумным.]
Чтобы добавить больше путаницы: если я отключаю триггер, это стоит 73% времени, нооставив старый триггер, упомянутый выше, без изменений, мой запрос все еще занимает много часов.Я не пробовал отключать триггер отметки времени.
Если посмотреть на план запроса при использовании быстрого триггера, соотношения практически одинаковы, но общее время чуть меньше.