Как провести рефакторинг триггера, который использует вставленные и удаленные таблицы, чтобы переместить общий код в хранимую процедуру

У меня есть триггер, который будет создаваться динамически, так как он будет прикреплен к представлению, которое также создается динамически. Я не хочу, чтобы в моей хранимой процедуре был весь триггер, поэтому я хотел бы переместить большую часть его в хранимую процедуру, но я не буду знать поля во вставленных и удаленных таблицах.

Длина триггера составляет около 90 строк, и единственное, что мне действительно нужно различать между триггерами, это:

DECLARE @DEBUG bit = 1
DECLARE @EntityName nvarchar(128) = 'Lot'
    SELECT * INTO #MYINSERTED FROM INSERTED
    SELECT * INTO #MYDELETED FROM DELETED

Если бы я мог переместить остальную часть в хранимую процедуру, это было бы здорово.

Проблема с простой передачей @DEBUG и @EntityName и использованием #MYINSERTED и #MYDELETED в хранимой процедуре, тогда у меня будет проблема, если два человека вставляют или обновляют одно и то же представление одновременно.

Лучше всего передать табличную переменную, чтобы устранить любые проблемы с параллелизмом, но я не уверен, как это лучше всего сделать.

Спасибо.


person James Black    schedule 03.06.2009    source источник


Ответы (2)


На самом деле это было бы плохой идеей. SQL не похож на обычный процедурный язык. «Компиляция» SQL привязывается к плану физического пути доступа, что означает, что операторы компилируются в планы, в которых говорится «открыть набор строк с идентификатором 1234, выполнить поиск записи и получить ее содержимое», и что «1234» определяется во время компиляция пакета оптимизатором. Это означает, что включение общего кода в процедуру по мере вашего планирования чаще приносит больше вреда, чем пользы. Процедура не может быть привязана к «общему» пути доступа, ей необходимо знать фактические таблицы и объекты, которые она должна искать для выбора, обновлений и тому подобного. Вы либо выполняете динамический SQL в процедуре, либо перемещаете только общие части процедуры, не связанные с данными (например, вычисления), что создает очень запутанный код и все еще может снизить производительность, в то же время уменьшая Читаемость процедуры.

Намного более желательно иметь шаблон и генерировать триггеры из этого шаблона с помощью различных методов генерации кода, таких как XML и XSLT.

person Remus Rusanu    schedule 03.06.2009
comment
У меня много динамического sql в триггере, так как таблицы, которые будут задействованы, неизвестны, пока не будет выполнена вставка / обновление. Я бы хотел, чтобы динамический sql был в хранимой процедуре, так как я бы предпочел, чтобы мой триггер был как можно более простым, поскольку я считаю, что хранимые процедуры легче тестировать. Может ли хранимая процедура генерировать триггер из XML и XSLT? Все это происходит в базе данных, я не могу допустить, чтобы это происходило на более высоком уровне. - person James Black; 03.06.2009
comment
Вы можете привязать генерацию триггера к триггеру DDL (msdn.microsoft.com/en -us / library / ms190989.aspx) и сгенерировать нединамический триггер вовремя в ответ на создание таблицы. - person Remus Rusanu; 03.06.2009
comment
кстати, если вы не можете сгенерировать триггер прямо внутри триггера DDL по разным причинам (контекст транзакции, ссылки еще не доступны), вы можете использовать уведомления о событиях (msdn.microsoft.com/en-us/library/ms182602.aspx) вместо этого, если вы можете терпеть небольшой период" открытого "состояния таблицы (т. е. . нет связанного с ним триггера) сразу после создания / изменения. - person Remus Rusanu; 03.06.2009

Я подозреваю, что метаданные / схемы о inserted и deleted являются основной проблемой здесь (вот почему вы используете SELECT * INTO).

Если вы создаете код, генерирующий триггер и просматривающий динамически, я бы сказал, что это, вероятно, не имеет большого значения. В конце концов, все триггеры и представления генерируются кодом и могут быть регенерированы по мере того, как ваша система получает новые возможности или улучшается основной SP.

Только если триггеры и представления настроены и никогда не регенерируются, тогда будет преимущество совместного использования основного SP, который можно изменять и обновлять, вместо повторного создания представлений и триггеров.

Накладные расходы на регенерацию, вероятно, перевешиваются сгенерированным кодом, который будет иметь четкий план выполнения и лучшую привязку.

person Cade Roux    schedule 03.06.2009
comment
Я не ожидаю, что основная часть триггера будет переработана, и если это так, было бы проще зафиксировать одну хранимую процедуру, чтобы все ссылающиеся триггеры получили новое изменение в качестве побочного эффекта. Меня беспокоит, что вы правы, может быть проще просто держать триггер вместе и динамически генерировать все, но я надеюсь, что есть лучшее решение. По крайней мере, я могу увидеть, может ли хранимая процедура, которая создает представление / триггер, получить sql из файла и изменить значение @EntityName, поскольку это единственное различие между таблицами. - person James Black; 03.06.2009
comment
Ваш SP, который генерирует код, может делать все, что угодно. У меня есть SP, которые вставляют строки в управляющие таблицы, создают SP и таблицы для использования этими SP и все такое. SP в основном генерирует всю структуру для конкретного процесса на основе шаблона. - person Cade Roux; 03.06.2009