36.11. Informação de otimização de função #

Por padrão, uma função é apenas uma caixa preta, cujo comportamento o sistema de banco de dados sabe muito pouco. Assim, isto significa que consultas que usam função podem ser executadas com muito menos eficiência do que poderiam ser executadas. É possível fornecer conhecimentos adicionais que ajudam o planejador a otimizar as chamadas de função.

Alguns fatos básicos podem ser fornecidos por anotações declarativas incluídas no comando CREATE FUNCTION. O mais importante é a categoria de volatilidade da função (IMMUTABLE, STABLE, ou VOLATILE); deve-se sempre ter o cuidado de especificar a volatilidade corretamente ao definir a função. A propriedade de segurança de paralelismo ( PARALLEL UNSAFE, PARALLEL RESTRICTED ou PARALLEL SAFE) também deve ser especificada, se for desejado usar a função em consultas paralelizadas. Também pode ser útil especificar o custo de execução estimado da função, e/ou o número de linhas que a função retornando conjunto deve retornar. Entretanto, a forma declarativa de especificar estes dois fatos permite apenas especificar um valor constante, muitas vezes inadequado.

Também é possível anexar uma função de suporte ao planejador a uma função que pode ser chamada pelo SQL (chamada de sua função de destino), e, assim, fornecer conhecimento sobre uma função de destino que é muito complexa para ser representada declarativamente. As funções de suporte do planejador devem ser escritas em C (embora suas funções de destino possam não ser), portanto, este é um recurso avançado que relativamente poucas pessoas vão usar.

Uma função de suporte ao planejador deve ter a assinatura SQL

supportfn(internal) returns internal

Ela é anexada à sua função de destino especificando a cláusula SUPPORT ao criar a função de destino.

Os detalhes da API para funções de suporte ao planejador podem ser encontrados na distribuição do código-fonte do PostgreSQL no arquivo src/include/nodes/supportnodes.h. Aqui é fornecida apenas uma visão geral do que as funções de suporte ao planejador podem fazer. O conjunto de solicitações possíveis para uma função de suporte é extensível, portanto, mais coisas podem ser possíveis em versões futuras.

Algumas chamadas de função podem ser simplificadas durante o planejamento com base nas propriedades específicas da função. Por exemplo, int4mul(n, 1) poderia ser simplificado para apenas n. Este tipo de transformação pode ser realizada por uma função de suporte ao planejador, fazendo com que ela implemente o tipo de solicitação SupportRequestSimplify. A função de suporte será chamada para cada instância da função de destino encontrada em uma árvore de análise da consulta. Se for descoberto que a chamada em particular pode ser simplificada em alguma outra forma, a função poderá construir e retornar uma árvore de análise representando esta expressão. Isto também funciona automaticamente para operadores baseados na função — no exemplo dado, n * 1 também seria simplificado para n. (Mas observe que é apenas um exemplo; na realidade, esta otimização específica não é executada pelo PostgreSQL padrão.) Não há garantia que o PostgreSQL nunca chamará a função de destino nos casos em que a função de suporte possa realizar a simplificação. Deve ser garantida a equivalência rigorosa entre a expressão simplificada e a execução real da função de destino.

Para funções de destino que retornam boolean, é geralmente útil estimar a fração de linhas selecionadas por uma cláusula WHERE usando esta função. Isto pode ser feito por uma função de suporte que implementa o tipo de solicitação SupportRequestSeletivity.

Se o tempo de execução da função de destino for altamente dependente de suas entradas, pode ser útil fornecer uma estimativa de custo variável para ela. Isto pode ser feito por uma função de suporte que implementa o tipo de solicitação SupportRequestCost.

Para funções de destino que retornam conjuntos, é geralmente útil fornecer uma estimativa variável para o número de linhas retornadas. Isto pode ser feito por uma função de suporte que implementa o tipo de solicitação SupportRequestRows.

Para funções de destino que retornam boolean, pode ser possível converter uma chamada de função que aparece na cláusula WHERE em uma cláusula ou cláusulas de operador indexável. As cláusulas convertidas podem ser exatamente equivalentes à condição da função, ou podem ser um pouco mais fracas (ou seja, podem aceitar alguns valores que a condição da função não aceitaria). No último caso, diz-se que a condição do índice é com perdas; a condição ainda pode ser usada para percorrer o índice, mas terá que ser executada a chamada da função para cada linha retornada pelo índice, para ver se a linha atende realmente a condição WHERE, ou não. Para criar estas condições, a função de suporte deve implementar o tipo de solicitação SupportRequestIndexCondition.