Basicamente, quero atribuir o resultado de uma consulta a um atributo de tipo personalizado. No entanto, notei que a consulta diretamente do console do PostgreSQL foi de cerca de 0,071 ms e dentro da função foi de 0,400 ms e 0,170 ms após algumas chamadas. explain analyze
ainda mostra o uso de índices no primeiro caso, mas não no segundo.
Aqui está o que estou fazendo.
CREATE OR REPLACE FUNCTION fun_isliked(
par_client client.id%type,
par_feed feed.id%type
)
RETURNS boolean
AS
$$
BEGIN
RETURN (
EXISTS(
SELECT
1
FROM
feedlike fl
WHERE
fl.client = par_client
AND fl.feed = par_feed
AND fl.state = 1
)
);
END;
$$ LANGUAGE plpgsql STABLE;
Aqui estão as saídas dos explain analyze
dois casos descritos acima:
postgres=# explain analyze select exists (select 1 from feedlike where client = 13 and feed = 68 and state = 1);
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
Result (cost=8.30..8.31 rows=1 width=0) (actual time=0.037..0.037 rows=1 loops=1)
InitPlan 1 (returns $0)
-> Index Scan using feedlike_client_feed_unique on feedlike (cost=0.28..8.30 rows=1 width=0) (actual time=0.034..0.034 rows=1 loops=1)
Index Cond: ((client = 13) AND (feed = 68))
Filter: (state = 1)
Total runtime: 0.086 ms
postgres=# explain analyze select * from fun_isliked(13, 68);
QUERY PLAN
----------------------------------------------------------------------------------------------------------
Function Scan on fun_isliked (cost=0.25..0.26 rows=1 width=1) (actual time=0.398..0.398 rows=1 loops=1)
Total runtime: 0.416 ms
Qual é uma possível solução alternativa para obter efetivamente o mesmo tempo de execução dentro da função? É mesmo possível? Além disso, estou executando o PostgreSQL 9.3.
Descobri que essa pergunta no SO tinha o que eu precisava, mas depois de tentar de tudo na resposta selecionada e não ter sucesso em reduzir o tempo de execução, decidi fazer uma nova pergunta.
O elefante na sala é a sobrecarga de funções . Ao chamar uma função em vez de SQL bruto, o Postgres precisa procurar a função nos catálogos do sistema (possivelmente escolhendo a melhor correspondência em caso de sobrecarga de função) e considerar as configurações da função. E depois há a sobrecarga para a própria chamada de função. Isso adiciona um pequeno custo indireto.
Isso realmente importa apenas para consultas muito simples como o seu exemplo - que deve ser implementado com uma função SQL simples. Você ainda encontra alguma (minúscula) sobrecarga de função com uma função SQL, mas pode ser "embutida" se for simples
SELECT
e algumas pré-condições forem atendidas .Como sempre, as chamadas repetidas lucram com o cache preenchido. E no caso de funções plpgsql, ele também pode começar a usar um plano genérico após algumas (normalmente 5) chamadas, se isso parecer promissor.
Considere esta discussão relacionada em pgsql-general .
Planos de consulta para código dentro de funções plpgsql
Você está se perguntando:
As funções plpgsql são caixas pretas para o planejador de consulta, que não examina o conteúdo da função. Eles agem como barreiras de otimização. Ao contrário das funções SQL, seu conteúdo não pode ser embutido em consultas externas.
Esta é a razão pela qual
EXPLAIN ANALYZE
não mostra o que está acontecendo dentro da função plpgsql e, portanto, você não vê nenhuma varredura de índice. O índice (provavelmente) ainda é usado. Você pode usar o módulo adicionalauto_explain
para dar uma olhada nos planos de consulta para o código SQL dentro da função. Considere as respostas a esta pergunta relacionada para obter detalhes: