Seberapa sering pemicu UNTUK SETIAP PERNYATAAN akan dilaksanakan jika operasi disebabkan oleh kendala FK dengan UPDATE CASCADE?

11

Saya mengerti bahwa pemicu pada tabel t didefinisikan dengan FOR EACH STATEMENTakan berjalan sekali ketika saya menjalankan UPDATE t ....

Sekarang, ketika tdidefinisikan dengan FOREIGN KEY ... REFERENCES a ... ON UPDATE CASCADE, dan saya memperbarui N baris a, akankah hal itu menyebabkan pemicu dipanggil sekali, atau N kali?

Dengan kata lain, apakah perubahan pada tabel yang disebabkan oleh batasan FK lebih seperti satu UPDATE, atau lebih seperti serangkaian UPDATEs?

Hanno Fietz
sumber
4
Anda bisa membuat test case! Masukkan ke dalam tabel lain di tubuh pelatuk dan lihat berapa banyak baris yang Anda dapatkan. Kemudian tuliskan dalam jawaban Anda sendiri untuk pertanyaan ini (itu diizinkan, dianjurkan bahkan)!
Colin 't Hart
2
Kalimat terkemuka yang disebutkan FOR EACH STATEMENTadalah ortogonal untuk sisa pertanyaan. Kendala FK diimplementasikan dengan pemicu khusus FOR EACH ROW.
Erwin Brandstetter
1
@Erwin "FOR EACH ROW of a" atau "FOR EACH ROW of t"?
ypercubeᵀᴹ
@ ypercube: Saya menambahkan jawaban dengan detail.
Erwin Brandstetter

Jawaban:

6

Batasan kunci asing saat ini diimplementasikan dengan pemicu internal khusus. Semuanya dijalankan FOR EACH ROW.

Perhatikan bahwa ini adalah detail implementasi yang dapat berubah, jadi jangan bergantung padanya. Tetapi dasar-dasarnya tidak berubah selama beberapa versi utama terakhir, jadi perubahan besar tidak mungkin.

Saya menjalankan tes cepat dengan batasan FK sederhana dari tblke tbltype. FK sederhana diimplementasikan dengan empat pemicu internal sederhana FOR EACH ROWdalam pengujian saya di hal 9.4.
Berikut ini ikhtisar singkat tentang cara menyelidiki:

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'

Dua "noaksi" internal terpicu tbltype.
Dua "cek" internal diaktifkan tbl.
Semuanya dijalankan FOR EACH ROW, seperti yang ditunjukkan oleh angka ganjil di tgtype.

2 byte Postgres tgtype smallintmewakili int16kode sumber C di mana bit paling sedikit dikodekan TRIGGER_TYPE_ROW. Penjelasan terperinci di sini:

Anda dapat dengan mudah menguji ini dengan sepasang pemicu identik di mana Anda hanya mengubah FOR ROW/ STATEMENT...

Erwin Brandstetter
sumber
5

Itu mengeksekusi N kali, dan cara termudah untuk melihat ini adalah dengan mengeksekusi pernyataan tersebut EXPLAIN ANALYZE, yaitu

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

Ini akan memberi Anda informasi yang mirip dengan ini:

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

(diuji dengan 9.2)

Hanno Fietz
sumber
1
Ini agak mengejutkan bagi saya. Diuji pada 9,4 dengan hasil yang sama.
dezso