¿Hay alguna forma de deshabilitar un desencadenador de SQL Server solo para un ámbito de ejecución particular?


En SQL Server 2005, ¿hay una manera de que un disparador descubra qué objeto es responsable de disparar el disparador? Me gustaría usar esto para desactivar el disparador de un prodecure almacenado.

¿Hay alguna otra forma de desactivar el disparador solo para la transacción actual? Podría usar el siguiente código, pero si no me equivoco, también afectaría a las transacciones concurrentes, lo que sería algo malo.

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 } [ ; ]

Si es posible, me gustaría evitar la técnica de tener un campo "NoTrigger" en mi tabla y haciendo un NoTrigger = null, porque me gustaría mantener la tabla lo más pequeña posible.

La razón por la que me gustaría evitar el disparador es porque contiene lógica que es importante para las actualizaciones manuales de la tabla, pero mi procedimiento almacenado se encargará de esta lógica. Debido a que este será un procedimiento muy utilizado, quiero que sea rápido.

Los disparadores imponen una sobrecarga adicional en el servidor porque inician una transacción implícita. Tan pronto como se ejecuta un disparador, se inicia una nueva transacción implícita y cualquier recuperación de datos dentro de una transacción mantendrá bloqueos en las tablas afectadas.

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

Author: Cade Roux, 2008-10-06

11 answers

Acabo de ver este artículo recientemente resaltado en el boletín de SQL Server Central y parece ofrecer una forma que puede encontrar útil utilizando el Context_Info en la conexión:

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


EDITAR por Terrapin:

El enlace anterior incluye el siguiente código:

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  

Si desea evitar que se ejecute el disparador, puede hacer lo siguiente:

SET Context_Info 0x55555 
INSERT dbo.Table1 VALUES(100)
 56
Author: Cade Roux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-07 16:25:37

Si el desencadenador está causando problemas de rendimiento en la aplicación, el mejor enfoque es eliminar todas las actualizaciones manuales de la tabla y requerir que todas las actualizaciones pasen por los procedimientos almacenados insertar/actualizar que contienen la lógica de actualización correcta. A continuación, puede quitar el gatillo por completo.

Sugiero denegar los permisos de actualización de tabla si nada más funciona.

Esto también resuelve el problema del código duplicado. Duplicar código en el SP de actualización y en el disparador es un violación de los buenos principios de ingeniería de software y será un problema de mantenimiento.

 6
Author: Jeffrey L Whitledge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-06 15:33:48

ALTERAR TABLA tbl DESACTIVAR TRIGGER trg

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

No entiendo el significado de su 1er párrafo aunque

 4
Author: devio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-06 15:13:28

Dado que indica que el disparador contiene lógica para manejar todas las actualizaciones, incluso las actualizaciones manuales, entonces ahí debería ser donde reside la lógica. El ejemplo que mencionas, en el que un procedimiento almacenado "se encargará de esta lógica" implica código duplicado. Además, si desea asegurarse de que cada instrucción de ACTUALIZACIÓN tiene esta lógica aplicada independientemente del autor, entonces el desencadenador es el lugar para ello. ¿Qué sucede cuando alguien crea un procedimiento pero se olvida de duplicar la lógica una vez más? Lo sucede cuando es el momento de modificar la lógica?

 2
Author: Pittsburgh DBA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-06 15:38:09

No estoy seguro de si esto es una buena idea, pero parece funcionar para mí. Transaction debe evitar inserciones en la tabla desde otros procesos mientras trigger está deshabilitado.

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
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-10 20:30:32

No deshabilite el disparador. Usted está en lo correcto que se desactivará para cualquier transacción concurrente.

¿Por qué desea desactivar el disparador? ¿Qué hace? ¿Por qué el disparador es un problema? Por lo general, es una mala idea desactivar un tigger desde la perspectiva de la integridad de los datos.

 1
Author: HLGEM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-06 15:17:08

Considere reescribir el disparador para mejorar el rendimiento si el rendimiento es el problema.

 1
Author: HLGEM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-06 15:58:32

Me caí un poco en esto. Por un lado soy muy anti-trigger principalmente porque es un lugar más para mí para buscar código ejecutándose contra mi tabla, además de las razones indicadas en el artículo vinculado en la publicación de preguntas.

Por otro lado, si tiene lógica para hacer cumplir reglas de negocio estables e inmutables o acciones de tabla cruzada (como mantener una tabla de historial), entonces sería más seguro meter esto en un disparador para que los autores de procedimientos y programadores no necesiten lidiar con con él, simplemente funciona.

Por lo tanto, mi recomendación es poner la lógica necesaria en su trigger en lugar de en este proc que, inevitablemente, crecerá a varios procs con la misma exención.

 1
Author: Rob Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-06 19:53:47

Acabo de enfrentarme al mismo problema y se me ocurrió la siguiente solución, que funciona para mí.

  1. Cree una tabla de base de datos permanente que contenga un registro para cada disparador que desee deshabilitar( por ejemplo, refTriggerManager); cada fila contiene el nombre del disparador (por ejemplo, strTriggerName = 'MyTrigger') y una bandera de bits (por ejemplo, blnDisabled, valor predeterminado: 0).

  2. Al principio del cuerpo del disparador, busca strTriggerName = 'MyTrigger' en refTriggerManager. Si blnDisabled = 1, luego regrese sin ejecutar el resto del código del disparador, de lo contrario continúe con el código del disparador hasta completarlo.

  3. En el proceso almacenado en el que desea desactivar el desencadenador, haga lo siguiente:


INICIAR TRANSACCIÓN

UPDATE refTriggerManager SET blnDisabled = 1 WHERE strTriggerName = 'MyTrigger'

/* ACTUALICE la tabla que posee 'MyTrigger', pero que desea desactivar. Desde refTriggerManager.blnDisabled = 1,' MyTrigger ' devuelve sin ejecutar su código. */

UPDATE refTriggerManager SET blnDisabled = 0 WHERE triggerName = 'MyTrigger'

/* Código de actualización final opcional que activa trigger. Desde refTriggerManager.blnDisabled = 0, 'MyTrigger' se ejecuta por completo. */

COMMIT TRANSACTION


Todo esto tiene lugar dentro de una transacción, por lo que está aislado del mundo exterior y no afectará a otras actualizaciones en la tabla de destino.

¿alguien ve algún problema con esto ¿acercarnos?

Bill

 0
Author: Hoyacoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-05 04:07:50

Estoy de acuerdo con algunas otras respuestas. No desactive el disparador.

Esto es pura opinión, pero evito desencadenantes como la peste. He encontrado muy pocos casos en los que se utilizó un disparador para hacer cumplir las reglas de la base de datos. Hay casos obvios en mi experiencia, y solo tengo mi experiencia sobre la cual hacer esta declaración. Por lo general, he visto disparadores utilizados para insertar algunos datos relacionales (que debe hacerse desde la lógica de negocio), para insertar datos en la tabla de informes es decir desnormalización de los datos (que se puede hacer con un proceso fuera de la transacción), o para transformar los datos de alguna manera.

Hay usos legítimos para los disparadores, pero creo que en la programación diaria de negocios son pocos y distantes entre sí. Esto puede no ayudar en su problema actual, pero usted podría considerar la eliminación del gatillo por completo y lograr el trabajo que el gatillo está haciendo de alguna otra manera.

 0
Author: Jason Jackson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-23 02:56:30

Puede utilizar 'Exec' función a diable y activar disparadores desde un procedimiento almacenado. Ejemplo: EXEC ('ENABLE TRIGGER dbo.TriggerName on dbo.TriggeredTable')

 0
Author: Nader Sghir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-10 16:12:10