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

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

Длина триггера составляет около 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)


arrow_upward
4
arrow_downward

На самом деле это было бы плохой идеей. 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

arrow_upward
0
arrow_downward

Я подозреваю, что метаданные / схемы о 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