Muitas coisas que podem ser feitas usando gatilhos, também podem
ser implementadas usando o sistema de regras do
PostgreSQL.
Uma das coisas que não podem ser implementadas por regras são alguns
tipos de restrições, especialmente chaves estrangeiras.
É possível colocar uma regra qualificada que reescreve um comando
para NOTHING, se o valor de uma coluna não
aparecer em outra tabela.
Mas então os dados são silenciosamente jogados fora, e isto não
é uma boa ideia.
Se forem necessárias verificações de valores válidos e, no caso de
surgir um valor inválido, for gerada uma mensagem de erro, isto
deverá ser feito por um gatilho.
Neste capítulo, o foco está no uso de regras para atualizar visões.
Todos os exemplos de regra de atualização neste capítulo também
podem ser implementados usando gatilhos INSTEAD OF
nas visões.
Escrever estes gatilhos é geralmente mais fácil do que escrever
regras, especialmente se for necessária uma lógica complexa para
executar a atualização.
Para as coisas que podem ser implementadas por ambos, qual é o melhor depende do uso do banco de dados. O gatilho é disparado uma vez para cada linha afetada. A regra modifica a consulta, ou gera uma consulta adicional. Portanto, se forem afetadas muitas linhas em uma instrução, uma regra que gera um comando extra provavelmente será mais rápida do que um gatilho chamado para cada linha devendo determinar novamente o que fazer várias vezes. No entanto, a abordagem de gatilho é conceitualmente muito mais simples do que a abordagem de regra, sendo mais fácil para os novatos acertarem.
A seguir está mostrado um exemplo de como a escolha de regras versus gatilhos funciona em uma situação. Existem duas tabelas:
CREATE TABLE computador (
hospedeiro text, -- indexado
fabricante text -- indexado
);
CREATE TABLE software (
software text, -- indexado
hospedeiro text -- indexado
);
As duas as tabelas possuem muitos milhares de linhas, e os índices
no hospedeiro são únicos.
A regra ou gatilho deve implementar uma restrição que exclua linhas
de software que fazem referência a um computador
excluído.
O gatilho usaria o seguinte comando:
DELETE FROM software WHERE hospedeiro = $1;
Uma vez que o gatilho é chamado para cada linha individual excluída
da tabela computador, pode-se preparar e salvar
o plano para este comando, e passar o valor de
hospedeiro no parâmetro.
A regra seria escrita como:
CREATE RULE computador_exclusão AS ON DELETE TO computador
DO DELETE FROM software WHERE hospedeiro = OLD.hospedeiro;
Agora, veremos diferentes tipos de exclusões. No caso de
DELETE FROM computador WHERE hospedeiro = 'mypc.local.net';
a tabela computador é verificada pelo índice
(rápido), e o comando emitido pelo gatilho também usaria uma
verificação de índice (também rápida).
O comando extra da regra seria:
DELETE FROM software WHERE computador.hospedeiro = 'mypc.local.net'
AND software.hospedeiro = computador.hospedeiro;
Uma vez que existem índices apropriados definidos, o planejador irá criar o plano
Nestloop -> Index Scan using comp_hostidx on computador -> Index Scan using soft_hostidx on software
Portanto, não haveria muita diferença de velocidade entre o gatilho e a implementação da regra.
Na próxima exclusão desejamos nos livrar de todos os 2000
computadores onde hospedeiro
começa com old.
Existem dois comandos possíveis para fazer isto.
Um é:
DELETE FROM computador WHERE hospedeiro >= 'old'
AND hospedeiro < 'ole'
O comando adicionado pela regra será
DELETE FROM software WHERE computador.hospedeiro >= 'old' AND computador.hospedeiro < 'ole'
AND software.hospedeiro = computador.hospedeiro;
com o plano
Hash Join
-> Seq Scan on software
-> Hash
-> Index Scan using comp_hostidx on computador
O outro comando possível é
DELETE FROM computador WHERE hospedeiro ~ '^old';
que resulta no seguinte plano de execução para o comando adicionado pela regra:
Nestloop -> Index Scan using comp_hostidx on computador -> Index Scan using soft_hostidx on software
Isto mostra que o planejador não percebe que a qualificação para
hospedeiro em computador
também pode ser usada para uma varredura de índice em
software quando há várias expressões de
qualificação combinadas com AND, que é o que é
feito na versão do comando com expressão regular.
O gatilho será chamado uma vez para cada um dos 2.000 computadores
antigos que precisam ser excluídos, resultando em uma varredura de
índice em computador e 2.000 varreduras de índice
em software.
A implementação da regra fará isto com dois comandos que usam índices.
E depende do tamanho geral da tabela software
se a regra ainda será mais rápida na situação de varredura sequencial.
As 2.000 execuções de comandos do gatilho no gerenciador SPI levam
algum tempo, mesmo que todos os blocos de índice logo estejam no
cache.
O último comando que examinaremos é:
DELETE FROM computador WHERE fabricante = 'bim';
Novamente, isto pode resultar na exclusão de muitas linhas da tabela
computador.
Portanto, o gatilho executará novamente muitos comandos por meio
do executor.
O comando gerado pela regra será:
DELETE FROM software WHERE computador.fabricante = 'bim'
AND software.hospedeiro = computador.hospedeiro;
O plano para este comando será novamente o laço aninhado em duas
varreduras de índice, usando apenas um índice diferente em
computador:
Nestloop -> Index Scan using comp_manufidx on computador -> Index Scan using soft_hostidx on software
Em qualquer um desses casos, os comandos extras do sistema de regras serão mais ou menos independentes do número de linhas afetadas no comando.
O resumo é que as regras só serão muito mais lentas do que os gatilhos se suas ações resultarem em junções grandes e mal qualificadas, uma situação em que o planejador falha.