36.7. Categorias de volatilidade de função #

Toda função tem uma classificação de volatilidade, com as seguintes possibilidades: VOLATILE, STABLE ou IMMUTABLE. VOLATILE é o padrão quando o comando CREATE FUNCTION não especifica a categoria. A categoria da volatilidade é uma promessa feita ao otimizador sobre o comportamento da função:

Para melhores resultados de otimização, as funções devem ser rotuladas com a categoria de volatilidade mais estrita válida para elas.

Qualquer função com efeitos colaterais deve ser rotulada como VOLATILE, de modo que as chamadas para ela não possam ser otimizadas. Mesmo uma função sem efeitos colaterais precisa ser rotulada como VOLATILE, se o seu valor puder mudar na mesma consulta; alguns exemplos são random(), currval() e timeofday().

Outro exemplo importante é a família de funções current_timestamp poder se qualificar como STABLE, porque seus valores não mudam dentro da transação.

Há relativamente pouca diferença entre as categorias STABLE e IMMUTABLE ao considerar consultas interativas simples, que são planejadas e executadas imediatamente: não importa muito se uma função é executada uma vez durante o planejamento, ou uma vez durante a inicialização da execução da consulta. Mas há uma grande diferença se o plano for salvo e reutilizado posteriormente. Rotular uma função como IMMUTABLE, quando na verdade não é, pode permitir que ela seja convertida prematuramente para uma constante durante o planejamento, fazendo com que um valor obsoleto seja reutilizado durante os usos subsequentes do plano. Isto é um perigo ao usar instruções preparadas, ou ao usar linguagens de função que armazenam planos (tal como o PL/pgSQL).

Para funções escritas em SQL, ou em qualquer uma das linguagens procedurais padrão, há uma segunda propriedade importante determinada pela categoria de volatilidade, ou seja, a visibilidade de quaisquer alterações nos dados feitas pelo comando SQL que está chamando a função. Uma função VOLATILE verá estas mudanças, uma função STABLE ou IMMUTABLE não verá. Este comportamento é implementado usando o comportamento de instantâneo do MVCC (veja Controle de concorrência): As funções STABLE e IMMUTABLE usam o instantâneo estabelecido desde o início da consulta chamadora, enquanto as funções VOLATILE obtêm um novo instantâneo no início de cada consulta que executam.

Nota

As funções escritas em C podem gerenciar instantâneos como quiserem, mas é geralmente uma boa ideia fazer as funções C funcionarem dessa forma também.

Devido a este comportamento de captura de instantâneo, uma função contendo apenas comandos SELECT pode ser marcada com segurança como STABLE, mesmo se selecionar tabelas que possam estar sofrendo modificações por consultas simultâneas. O PostgreSQL executará todos os comandos de uma função STABLE usando o instantâneo estabelecido para a consulta chamadora, portanto, verá uma visão fixa do banco de dados durante esta consulta.

O mesmo comportamento de instantâneo é usado para comandos SELECT nas funções IMMUTABLE. Geralmente não é recomendável selecionar tabelas de banco de dados numa função IMMUTABLE, porque a imutabilidade será quebrada se o conteúdo da tabela mudar. No entanto, o PostgreSQL não impõe que não se faça isto.

Um erro comum é rotular uma função como IMMUTABLE, quando seus resultados dependem de um parâmetro de configuração. Por exemplo, uma função que manipula carimbos de data e hora podem ter resultados que dependem da configuração de TimeZone. Por segurança, estas funções devem ser rotuladas como STABLE.

Nota

O PostgreSQL requer que as funções STABLE e IMMUTABLE não contenham nenhum comando SQL além do SELECT, para prevenir a modificação de dados. (Este não é um teste inteiramente seguro, já que estas funções ainda podem chamar funções VOLATILE que modificam o banco de dados. Se isto for feito, vai se descobrir que a função STABLE ou IMMUTABLE não percebe as alterações no banco de dados aplicadas pela função chamada, porque elas estão ocultas de seu instantâneo.)