Jak często wyzwalacz FOR EACH DEKLARACJA będzie wykonywany, jeśli operacja jest spowodowana ograniczeniem FK przy użyciu UPDATE CASCADE?

11

Rozumiem, że wyzwalacz w tabeli t zdefiniowanej za pomocą FOR EACH STATEMENTzostanie uruchomiony raz, gdy wykonam polecenie an UPDATE t ....

Teraz, kiedy tzostanie zdefiniowane za pomocą FOREIGN KEY ... REFERENCES a ... ON UPDATE CASCADEi zaktualizuję N wierszy a, czy spowoduje to, że wyzwalacz zostanie wywołany raz, czy N razy?

Innymi słowy, czy zmiany w tabeli kaskadowane przez ograniczenie FK są bardziej podobne do pojedynczego UPDATE, czy raczej do serii UPDATEs?

Hanno Fietz
źródło
4
Możesz stworzyć przypadek testowy! Wstaw do innej tabeli w ciele wyzwalacza i zobacz, ile masz rzędów. Następnie napisz to we własnej odpowiedzi na to pytanie (jest to dozwolone, nawet zalecane)!
Colin 't Hart
2
Wzmianka o wiodącym zdaniu FOR EACH STATEMENTjest prostopadła do reszty pytania. Ograniczenia FK są wdrażane za pomocą specjalnych wyzwalaczy FOR EACH ROW.
Erwin Brandstetter
1
@Erwin „DLA KAŻDEJ WIERSZY z” lub „DLA KAŻDEGO WIERSZA z”?
ypercubeᵀᴹ
@ypercube: Dodałem odpowiedź ze szczegółami.
Erwin Brandstetter

Odpowiedzi:

6

Ograniczenia klucza obcego są obecnie wdrażane za pomocą specjalnych wewnętrznych wyzwalaczy. Wszystkie są uruchomione FOR EACH ROW.

Pamiętaj, że są to szczegóły implementacji, które można zmienić, więc nie polegaj na tym. Ale podstawy nie zmieniły się w ciągu ostatnich kilku głównych wersji, więc poważne zmiany są mało prawdopodobne.

Przeprowadziłem szybki test z prostym ograniczeniem FK od tbldo tbltype. Prosty FK jest implementowany z czterema prostymi wewnętrznymi wyzwalaczami FOR EACH ROWw moim teście na str. 9.4.
Oto krótki przegląd tego, jak przeprowadzić dochodzenie:

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'

Włączone są dwa wewnętrzne „bezczynności” tbltype.
Włączone dwa wewnętrzne „sprawdzanie” tbl.
Wszystkie są uruchamiane FOR EACH ROW, jak wskazują nieparzyste liczby w tgtype.

2 bajty Postgres tgtype smallintreprezentują int16kod źródłowy w C, w którym kodowany jest najmniej znaczący bit TRIGGER_TYPE_ROW. Szczegółowe wyjaśnienie tutaj:

Można łatwo sprawdzić to z pary identycznych wyzwalaczy gdzie jedyną zmianą FOR ROW/ STATEMENT...

Erwin Brandstetter
źródło
5

Wykonuje N razy, a najłatwiejszym sposobem, aby to sprawdzić, jest wykonanie instrukcji z EXPLAIN ANALYZEnapisem poprzedzającym, tj

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

Otrzymasz informacje podobne do tego:

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

(testowany z 9.2)

Hanno Fietz
źródło
1
To mnie trochę zaskakuje. Testowany na 9.4 z tymi samymi wynikami.
dezso