Есть ли способ отключить триггер SQL Server только для определенной области выполнения? - PullRequest
35 голосов
/ 06 октября 2008

В SQL Server 2005 есть ли способ для триггера выяснить, какой объект отвечает за срабатывание триггера? Я хотел бы использовать это для отключения триггера для одной сохраненной процедуры.

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

DISABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } ON { object_name | DATABASE | ALL SERVER } [ ; ]

ENABLE TRIGGER { [ schema_name . ] trigger_name [ ,...n ] | ALL } ON { object_name | DATABASE | ALL SERVER } [ ; ]

Если возможно, я бы хотел избежать использования метода «NoTrigger» в моей таблице и выполнения NoTrigger = null, потому что я хотел бы, чтобы таблица была как можно меньше.

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

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

От: http://searchsqlserver.techtarget.com/tip/1,289483,sid87_gci1170220,00.html#trigger

Ответы [ 11 ]

57 голосов
/ 07 октября 2008

Я только что видел эту статью, недавно выделенную в новостной рассылке SQL Server Central, и она предлагает способ, который может оказаться полезным при использовании Context_Info для соединения:

http://www.mssqltips.com/tip.asp?tip=1591


РЕДАКТИРОВАТЬ Terrapin:

Приведенная выше ссылка включает в себя следующий код:

USE AdventureWorks;  
GO  
-- creating the table in AdventureWorks database  
IF OBJECT_ID('dbo.Table1') IS NOT NULL  
DROP TABLE dbo.Table1  
GO  
CREATE TABLE dbo.Table1(ID INT)  
GO   
-- Creating a trigger  
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE  
AS  
DECLARE @Cinfo VARBINARY(128)  
SELECT @Cinfo = Context_Info()  
IF @Cinfo = 0x55555  
RETURN  
PRINT 'Trigger Executed'  
-- Actual code goes here  
-- For simplicity, I did not include any code  
GO  

Если вы хотите предотвратить запуск триггера, вы можете сделать следующее:

SET Context_Info 0x55555 
INSERT dbo.Table1 VALUES(100)
6 голосов
/ 06 октября 2008

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

Я предлагаю отказать в разрешении на обновление таблицы, если больше ничего не работает.

Это также решает проблему дублирования кода. Дублирование кода в пакете обновления SP и в триггере является нарушением хороших принципов разработки программного обеспечения и будет проблемой обслуживания.

4 голосов
/ 06 октября 2008

ALTER TABLE TABL DISABLE TRIGGER trg

http://doc.ddart.net/mssql/sql70/aa-az_5.htm

Я не понимаю смысла вашего первого абзаца, хотя

2 голосов
/ 25 февраля 2011

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

IF OBJECT_ID('dbo.TriggerTest') IS NOT NULL
 DROP PROCEDURE dbo.TriggerTest
GO

CREATE PROCEDURE [dbo].[TriggerTest]
AS
BEGIN TRANSACTION trnInsertTable1s
;
DISABLE TRIGGER trg_tblTable1_IU ON tblTable1
;
BEGIN -- Procedure Code
    PRINT '@@trancount'
    PRINT @@TRANCOUNT
    -- Do Stuff

END -- Procedure Code
;
ENABLE TRIGGER trg_tblTable1_IU ON tblTable1

IF @@ERROR <> 0 ROLLBACK TRANSACTION
ELSE COMMIT TRANSACTION
2 голосов
/ 06 октября 2008

Поскольку вы указываете, что триггер содержит логику для обработки всех обновлений, даже обновлений вручную, то именно там должна находиться логика. Пример, который вы упоминаете, в котором хранимая процедура «позаботится об этой логике» подразумевает дублирование кода. Кроме того, если вы хотите быть уверены, что в каждом операторе UPDATE эта логика применяется независимо от автора, то для нее используется триггер. Что происходит, когда кто-то создает процедуру, но снова забывает дублировать логику? Что происходит, когда пришло время изменить логику?

1 голос
/ 06 октября 2008

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

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

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

1 голос
/ 06 октября 2008

Подумайте о переписывании триггера, чтобы повысить производительность, если проблема в производительности.

1 голос
/ 06 октября 2008

Не отключайте триггер. Вы правы, что отключите все параллельные транзакции.

Почему вы хотите отключить триггер? Что оно делает? Почему триггер вызывает проблему? Обычно плохая идея отключать тигра с точки зрения целостности данных.

0 голосов
/ 10 декабря 2012

Вы можете использовать функцию ' Exec ' для вызова и включения триггеров из хранимой процедуры. Пример: EXEC ('ENABLE TRIGGER dbo.TriggerName on dbo.TriggeredTable')

0 голосов
/ 05 февраля 2010

Я только что столкнулся с той же проблемой и нашел следующее решение, которое работает для меня.

  1. Создать постоянную таблицу БД, содержащую одну запись для каждого триггера, который вы хотите отключить (например, refTriggerManager); каждая строка содержит имя триггера (например, strTriggerName = 'myTrigger') и битовый флаг (например, blnDisabled, по умолчанию 0).

  2. В начале тела триггера найдите strTriggerName = 'myTrigger' в refTriggerManager. Если blnDisabled = 1, вернитесь без выполнения остальной части кода триггера, иначе продолжите код триггера до завершения.

  3. В сохраненном процессе, в котором вы хотите отключить триггер, выполните следующие действия:


НАЧАЛО СДЕЛКИ

ОБНОВЛЕНИЕ refTriggerManager SET blnDisabled = 1 ГДЕ strTriggerName = 'myTrigger'

/ * ОБНОВИТЬ таблицу, которой принадлежит myTrigger, но которую вы хотите отключить. Поскольку refTriggerManager.blnDisabled = 1, myTrigger возвращается без выполнения своего кода. * /

ОБНОВЛЕНИЕ refTriggerManager SET blnDisabled = 0 ГДЕ triggerName = 'myTrigger'

/ * Необязательный окончательный код ОБНОВЛЕНИЯ, который запускает триггер. Поскольку refTriggerManager.blnDisabled = 0, myTrigger выполняется полностью. * /

совершение транзакции


Все это происходит внутри транзакции, поэтому она изолирована от внешнего мира и не повлияет на другие ОБНОВЛЕНИЯ на целевой таблице.

Кто-нибудь видит какие-либо проблемы с этим подходом?

Bill

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...