¿Con qué frecuencia se ejecutará un disparador PARA CADA DECLARACIÓN si la operación es causada por una restricción FK con ACTUALIZAR CASCADA?

11

Entiendo que un activador en la tabla t definido con FOR EACH STATEMENTse ejecutará una vez cuando ejecuto un UPDATE t ....

Ahora, cuando tse define con FOREIGN KEY ... REFERENCES a ... ON UPDATE CASCADE, y actualizo N filas a, ¿hará que se llame al disparador una vez, o N veces?

Dicho de otra manera, ¿los cambios en una tabla en cascada por una restricción FK se parecen más a una sola UPDATE, o más a una serie de UPDATEs?

Hanno Fietz
fuente
44
¡Podrías crear un caso de prueba! Inserte en otra tabla en el cuerpo del disparador y vea cuántas filas obtiene. ¡Entonces escríbalo en su propia respuesta a esta pregunta (eso está permitido, incluso alentado)!
Colin 't Hart
2
La oración principal que se menciona FOR EACH STATEMENTes ortogonal al resto de la pregunta. Las restricciones FK se implementan con desencadenantes especiales FOR EACH ROW.
Erwin Brandstetter
1
@Erwin "POR CADA FILA de un" o "POR CADA FILA de t"?
ypercubeᵀᴹ
@ypercube: agregué una respuesta con detalles.
Erwin Brandstetter

Respuestas:

6

Las restricciones de clave externa se implementan actualmente con activadores internos especiales. Todos ellos se ejecutan FOR EACH ROW.

Tenga en cuenta que estos son detalles de implementación que pueden cambiar, así que no confíe en ellos. Pero lo básico no ha cambiado en las últimas dos versiones principales, por lo que es poco probable que ocurran cambios importantes.

Ejecuté una prueba rápida con una simple restricción FK de tbla tbltype. Un FK simple se implementa con cuatro disparadores internos simples FOR EACH ROWen mi prueba en la página 9.4.
Aquí hay un resumen rápido sobre cómo investigar:

SELECT oid  -- 74791
FROM   pg_constraint
WHERE  conrelid = 'tbl'::regclass
AND    contype = 'f';

SELECT objid, classid::regclass  -- 74792,74793,74794,74795 / 'pg_trigger'
FROM   pg_depend
WHERE  refobjid = 74791
AND   deptype = 'i'

SELECT tgrelid::regclass, tgname, tgfoid, tgtype FROM pg_trigger
WHERE  oid IN (74792,74793,74794,74795) ORDER BY tgfoid;

'tbl'    ;'RI_ConstraintTrigger_c_74794';1644;5
'tbl'    ;'RI_ConstraintTrigger_c_74795';1645;17
'tbltype';'RI_ConstraintTrigger_a_74792';1654;9
'tbltype';'RI_ConstraintTrigger_a_74793';1655;17

SELECT oid, proname FROM pg_proc
WHERE oid IN (1654,1655,1644,1645);

1644;'RI_FKey_check_ins'
1645;'RI_FKey_check_upd'
1654;'RI_FKey_noaction_del'
1655;'RI_FKey_noaction_upd'

Se activan dos "nociones" internas tbltype.
Dos activadores internos de "verificación" activados tbl.
Todos ellos se ejecutan FOR EACH ROW, como lo indican los números impares en tgtype.

Los 2 bytes de Postgres tgtype smallintrepresentan un int16código fuente en C donde codifica el bit menos significativo TRIGGER_TYPE_ROW. Explicación detallada aquí:

Puede probar esto fácilmente con un par de disparadores idénticos donde solo cambia FOR ROW/ STATEMENT...

Erwin Brandstetter
fuente
5

Se ejecuta N veces, y la forma más fácil de ver esto es ejecutar la declaración con un EXPLAIN ANALYZEantecedente, es decir

EXPLAIN ANALYZE UPDATE a SET col = 1 WHERE othercol = 'foo';

Esto le dará información similar a esta:

Trigger for constraint t_col_fk on a: time=1.300 calls=9

(probado con 9.2)

Hanno Fietz
fuente
1
Esto es algo sorprendente para mí. Probado en 9.4 con los mismos resultados.
dezso