Медленное соединение для вставленных / удаленных триггерных таблиц

#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. Отличный момент для установки порога. Это может сделать триггер довольно сложным, но я полагаю, что есть компромиссы с чем угодно. Я все еще озадачен одним: у нас есть другая база данных, которая почти идентична, и она не испытывает такого замедления. Таблицы, триггеры и индексы кажутся идентичными, хотя я еще не проводил подробного сравнения.