Com que freqüência um gatilho FOR EACH STATEMENT será executado se a operação for causada por uma restrição de FK com UPDATE CASCADE?

11

Eu entendo que um gatilho na tabela t definido com FOR EACH STATEMENTserá executado uma vez quando eu executar um UPDATE t ....

Agora, quando té definido com FOREIGN KEY ... REFERENCES a ... ON UPDATE CASCADE, e eu atualizo N linhas a, isso fará com que o acionador seja chamado uma vez ou N vezes?

Em outras palavras, as alterações em uma tabela em cascata por uma restrição de FK são mais como uma única UPDATEou mais como uma série de UPDATEs?

Hanno Fietz
fonte
4
Você pode criar um caso de teste! Insira em outra tabela no corpo do gatilho e veja quantas linhas você obtém. Em seguida, escreva na sua própria resposta a esta pergunta (isso é permitido, até incentivado)!
Colin 'Hart
2
A frase principal mencionada FOR EACH STATEMENTé ortogonal ao resto da questão. As restrições de FK são implementadas com gatilhos especiais FOR EACH ROW.
Erwin Brandstetter
1
@Erwin "PARA CADA LINHA de um" ou "PARA CADA LINHA de t"?
ypercubeᵀᴹ
@ypercube: adicionei uma resposta com detalhes.
Erwin Brandstetter

Respostas:

6

Atualmente, as restrições de chave estrangeira são implementadas com gatilhos internos especiais. Todos eles são executados FOR EACH ROW.

Observe que esses são detalhes de implementação que podem mudar, portanto, não confie neles. Mas o básico não mudou nas últimas duas versões principais, portanto, mudanças importantes são improváveis.

Fiz um teste rápido com uma restrição FK simples de tblpara tbltype. Um FK simples é implementado com quatro gatilhos internos simples FOR EACH ROWno meu teste na página 9.4.
Aqui está um rápido resumo de como 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'

Dois "noaction" interno são ativados tbltype.
Dois "cheques" internos são ativados tbl.
Todos eles são executados FOR EACH ROW, conforme indicado pelos números ímpares em tgtype.

Os 2 bytes do Postgres tgtype smallintrepresentam um int16código fonte em C onde o bit menos significativo é codificado TRIGGER_TYPE_ROW. Explicação detalhada aqui:

Você pode facilmente testar isso com um par de gatilhos idênticos, onde você só muda FOR ROW/ STATEMENT...

Erwin Brandstetter
fonte
5

Ele executa N vezes, e a maneira mais fácil de ver isso é executar a instrução com um EXPLAIN ANALYZEanexo, ie

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

Isso fornecerá informações semelhantes a esta:

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

(testado com 9.2)

Hanno Fietz
fonte
1
Isso é algo surpreendente para mim. Testado em 9.4 com os mesmos resultados.
Dez26