Tengo un activador ACTUALIZAR en una tabla que vigila una columna específica que cambia de un valor específico a cualquier otro valor. Cuando esto sucede, actualiza algunos datos relacionados en otra tabla a través de una sola instrucción UPDATE.
Lo primero que hace el disparador es verificar si alguna fila actualizada tuvo el valor de esta columna cambiado del valor en cuestión. Simplemente se une INSERTED a DELETED y compara el valor en esa columna. Si nada califica, se rescata temprano para que la instrucción UPDATE no se ejecute.
IF NOT EXISTS (
SELECT TOP 1 i.CUSTNMBR
FROM INSERTED i
INNER JOIN DELETED d
ON i.CUSTNMBR = d.CUSTNMBR
WHERE d.CUSTCLAS = 'Misc'
AND i.CUSTCLAS != 'Misc'
)
RETURN
En este caso, CUSTNMBR es la clave principal de la tabla subyacente. Si hago una gran actualización en esta tabla (por ejemplo, más de 5000 filas), esta declaración toma EDADES, incluso si no he tocado la columna CUSTCLAS. Puedo ver cómo se detiene en esta declaración durante varios minutos en Profiler.
El plan de ejecución es extraño. Muestra una exploración insertada con 3.714 ejecuciones y ~ 18,5 millones de filas de salida. Eso se ejecuta a través de un filtro en la columna CUSTCLAS. Lo une (a través de un bucle anidado) a un Análisis eliminado (también filtrado en CUSTCLAS), que se ejecuta solo una vez y tiene 5000 filas de salida.
¿Qué idiota estoy haciendo aquí para causar esto? Tenga en cuenta que el desencadenante absolutamente debe manejar correctamente las actualizaciones de varias filas.
EDITAR :
También intenté escribirlo así (en caso de que EXISTS estuviera haciendo algo desagradable), pero sigue siendo igual de terrible.
DECLARE @CUSTNMBR varchar(31)
SELECT TOP 1 @CUSTNMBR = i.CUSTNMBR
FROM INSERTED i
INNER JOIN DELETED d
ON i.CUSTNMBR = d.CUSTNMBR
WHERE d.CUSTCLAS = 'Misc'
AND i.CUSTCLAS != 'Misc'
IF @CUSTNMBR IS NULL
RETURN
Respuestas:
Podría evaluar el uso de indicaciones explícitas
INNER MERGE JOIN
oINNER HASH JOIN
sugerencias, pero dado que presumiblemente está utilizando estas tablas nuevamente más adelante en el desencadenante, probablemente sea mejor simplemente insertando el contenidoinserted
y lasdeleted
tablas en las#temp
tablas indexadas y listo.No obtienen índices útiles creados para ellos automáticamente.
fuente
CUSTNMBR
para crear el índice agrupado único) y usar laOPTION (RECOMPILE)
sugerencia para que tenga en cuenta el número de filas o tal vez simplemente usar una convención de nomenclatura particular como#i_dbo_YourTable
#trigger_name_i
. Si voy con variables de tabla, tendré que abarrotar el código aún más con CREATE TABLE explícitas. Tenemos disparadores en cascada, pero no disparadores recursivos, así que creo que estaré a salvo ...OPTION (RECOMPILE)
para tener en cuenta la cardinalidad.Sé que esto se ha respondido, pero apareció como activo recientemente y también me he encontrado con esto para tablas con muchos millones de filas. Si bien no descarto la respuesta aceptada, al menos puedo agregar que mi experiencia muestra que un factor clave en el rendimiento del disparador al hacer pruebas similares (ver si una o más columnas han cambiado sus valores) es si las columnas ser probado fueron en realidad parte de la
UPDATE
declaración. Descubrí que comparar columnas entre las tablasinserted
ydeleted
que, de hecho, no formaban parte de laUPDATE
declaración, suponía un gran lastre para el rendimiento que, de lo contrario, no existiría si esos campos fueran parte deUPDATE
declaración (independientemente de que su valor se cambie realmente). ¿Por qué hacer todo ese trabajo (es decir, una consulta para comparar N campos en X filas) para determinar si algo ha cambiado si puede descartar lógicamente la posibilidad de que alguna de esas columnas se cambie, lo que obviamente no es posible si no estuvieran presentes? en laSET
cláusula de laUPDATE
declaración.La solución que empleé fue usar la función UPDATE () que solo funciona dentro de Triggers. Esta función incorporada le indica si se especificó una columna en la
UPDATE
instrucción y se puede usar para salir del activador si las columnas que le preocupan no son parte deUPDATE
. Esto se puede usar junto con aSELECT
para determinar si esas columnas, suponiendo que estén presentes en elUPDATE
, tienen cambios reales. Tengo un código en la parte superior de varios disparadores de auditoría que se ve así:Esta lógica procederá al resto del disparador si:
INSERT
SET
cláusula de unaUPDATE
y al menos una de esas columnas en una fila ha cambiadoEl
NOT (UPDATE...) OR NOT EXISTS()
podría parecer extraño o hacia atrás, pero está diseñado para evitar hacer elSELECT
de losinserted
ydeleted
las tablas si ninguna de las columnas relevantes son parte de laUPDATE
.Dependiendo de sus necesidades, la función COLUMNS_UPDATED () es otra opción para determinar qué columnas son parte de la
UPDATE
declaración.fuente
UPDATE(CUSTCLAS)
y simplemente omitir todo si es falso (+1). No creo que tenga razón en que las columnas no actualizadas no están tan disponibles en las versiones de fila como las actualizadas.tempdb
conDBCC PAGE
tempdb
, acabo de probar este script , pegué el resultado en el bloc de notas y busqué "EEEEEE". Veo el resultado en la captura de pantalla aquí . Tenga en cuenta versiones anteriores y posteriores de ambas columnas en ambas filas. ¡Puede haber formas mucho más fáciles pero suficientes para mis propósitos aquí!tempdb
páginas que no están al lado deBBBBBB
oDDDDDD
. ¡Podría tener que investigar un poco más! Aunque tal vez esto se deba a laREPLICATE
llamada.Podría intentar reescribir usando si existe
fuente
http://dave.brittens.org/blog/writing-well-behaved-triggers.html
Según Dave, debe usar tablas temporales o variables de tabla con índices, porque las tablas virtuales INSERTED / DELETED no tienen ninguna. Si tiene la posibilidad de disparadores recursivos, entonces debe usar variables de tabla para evitar colisiones de nombres.
Espero que alguien encuentre esto útil ya que la publicación original fue hace bastante tiempo ...
fuente
El siguiente código puede aumentar el rendimiento de este activador. No conocía el tipo de datos correcto de la columna [custclass] , por lo que debe ajustarlo.
Tenga en cuenta que puede incluir columnas adicionales en estas en copias de memoria de las tablas insertadas y eliminadas si las necesita en su código de activación. Las claves principales en estas tablas aumentarán en gran medida el rendimiento de la unión al actualizar más de unas pocas filas a la vez. ¡Buena suerte!
fuente