Wie oft wird ein FOR EACH STATEMENT-Trigger ausgeführt, wenn die Operation durch eine FK-Einschränkung mit UPDATE CASCADE verursacht wird?

11

Ich verstehe, dass ein Trigger für die mit definierte Tabelle t FOR EACH STATEMENTeinmal ausgeführt wird, wenn ich eine ausführe UPDATE t ....

Wenn nun tdefiniert FOREIGN KEY ... REFERENCES a ... ON UPDATE CASCADEist und ich N Zeilen aktualisiere a, wird der Trigger dann einmal oder N-mal aufgerufen?

Anders ausgedrückt: Sind Änderungen an einer Tabelle, die durch eine FK-Einschränkung kaskadiert werden, eher wie eine einzelne UPDATEoder eher wie eine Reihe von UPDATEs?

Hanno Fietz
quelle
4
Sie könnten einen Testfall erstellen! Fügen Sie in eine andere Tabelle im Hauptteil des Triggers ein und sehen Sie, wie viele Zeilen Sie erhalten. Dann schreibe es in deine eigene Antwort auf diese Frage (das ist erlaubt, sogar ermutigt)!
Colin 't Hart
2
Der erste Satz, der erwähnt FOR EACH STATEMENTwird , ist orthogonal zum Rest der Frage. FK-Einschränkungen werden mit speziellen Triggern implementiert FOR EACH ROW.
Erwin Brandstetter
1
@Erwin "FÜR JEDE REIHE von a" oder "FÜR JEDE REIHE von t"?
Ypercubeᵀᴹ
@ypercube: Ich habe eine Antwort mit Details hinzugefügt.
Erwin Brandstetter

Antworten:

6

Fremdschlüsseleinschränkungen werden derzeit mit speziellen internen Triggern implementiert. Alle von ihnen werden ausgeführt FOR EACH ROW.

Beachten Sie, dass dies Implementierungsdetails sind, die sich ändern können. Verlassen Sie sich also nicht darauf. Die Grundlagen haben sich in den letzten Hauptversionen jedoch nicht geändert, sodass größere Änderungen unwahrscheinlich sind.

Ich habe einen Schnelltest mit einer einfachen FK-Einschränkung von tblbis durchgeführt tbltype. In FOR EACH ROWmeinem Test auf Seite 9.4 ist eine einfache FK mit vier einfachen internen Triggern implementiert .
Hier ist ein kurzer Überblick über die Untersuchung:

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'

Zwei interne "noaction" werden ausgelöst tbltype.
Zwei interne "Check" -Trigger werden aktiviert tbl.
Alle von ihnen werden ausgeführt FOR EACH ROW, wie durch ungerade Zahlen in angezeigt tgtype.

Die 2 Bytes der Postgres tgtype smallintstellen einen int16In-C-Quellcode dar, in dem das niedrigstwertige Bit codiert TRIGGER_TYPE_ROW. Detaillierte Erklärung hier:

Sie können dies leicht mit einem Paar identischer Trigger testen, bei denen Sie nur FOR ROW/ STATEMENT...

Erwin Brandstetter
quelle
5

Es wird N-mal ausgeführt, und der einfachste Weg, dies zu sehen, besteht darin, die Anweisung mit einem EXPLAIN ANALYZEvorangestellten Befehl auszuführen , d. H.

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

Dadurch erhalten Sie ähnliche Informationen:

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

(getestet mit 9.2)

Hanno Fietz
quelle
1
Das ist etwas überraschend für mich. Getestet am 9.4 mit den gleichen Ergebnissen.
Dekso