Vindo de um histórico do MySQL, onde o desempenho do procedimento armazenado (artigo antigo) e a usabilidade são questionáveis, estou avaliando o PostgreSQL para um novo produto para minha empresa.
Uma das coisas que eu gostaria de fazer é mover parte da lógica do aplicativo para os procedimentos armazenados, portanto, estou aqui pedindo DOs e NÃO (melhores práticas) sobre o uso de funções no PostgreSQL (9.0), especificamente sobre problemas de desempenho.
postgresql
best-practices
plpgsql
Derek Downey
fonte
fonte
Respostas:
Estritamente falando, o termo "procedimentos armazenados" aponta para procedimentos SQL no Postgres, introduzidos no Postgres 11.
Também existem funções , fazendo quase, mas não exatamente o mesmo, e essas existem desde o início.
Funções com
LANGUAGE sql
são basicamente apenas arquivos em lote com comandos SQL simples em um wrapper de função (e, portanto, atômico, sempre executado dentro de uma única transação), aceitando parâmetros. Todas as instruções em uma função SQL são planejadas de uma vez , o que é sutilmente diferente de executar uma instrução após a outra e pode afetar a ordem na qual os bloqueios são executados.Para qualquer coisa mais, a linguagem mais madura é PL / pgSQL (
LANGUAGE plpgsql
). Funciona bem e foi aprimorado a cada versão na última década, mas serve melhor como cola para comandos SQL. Não se destina a cálculos pesados (exceto com comandos SQL).As funções PL / pgSQL executam consultas como instruções preparadas . A reutilização de planos de consulta em cache reduz algumas sobrecargas de planejamento e as torna um pouco mais rápidas que as instruções SQL equivalentes, o que pode ser um efeito perceptível dependendo das circunstâncias. Também pode ter efeitos colaterais, como nesta pergunta relacionada:
Isso traz as vantagens e desvantagens das declarações preparadas - conforme discutido no manual . Para consultas sobre tabelas com distribuição de dados irregular e parâmetros variáveis SQL dinâmica com
EXECUTE
pode ter um melhor desempenho quando o ganho de um plano de execução otimizado para o parâmetro dado (s) supera o custo de re-planejamento.Desde o Postgres 9.2, os planos de execução genéricos ainda são armazenados em cache para a sessão, mas, citando o manual :
Nós obtemos o melhor dos dois mundos na maioria das vezes (menos alguns custos adicionais) sem (ab) usar
EXECUTE
. Detalhes em O que há de novo no PostgreSQL 9.2 do PostgreSQL Wiki .O Postgres 12 apresenta a variável de servidor
plan_cache_mode
adicional para forçar planos genéricos ou personalizados. Para casos especiais, use com cuidado.Você pode ganhar muito com as funções do lado do servidor que impedem viagens adicionais de ida e volta ao servidor de banco de dados do seu aplicativo. Faça com que o servidor execute o máximo possível de uma só vez e retorne apenas um resultado bem definido.
Evite aninhar funções complexas, especialmente funções de tabela (
RETURNING SETOF record
ouTABLE (...)
). Funções são caixas pretas que se apresentam como barreiras de otimização para o planejador de consultas. Eles são otimizados separadamente, não no contexto da consulta externa, o que simplifica o planejamento, mas pode resultar em planos menos que perfeitos. Além disso, o custo e o tamanho do resultado das funções não podem ser previstos com confiabilidade.A exceção a esta regra são funções SQL simples (
LANGUAGE sql
), que podem ser "incorporadas" - se algumas pré-condições forem atendidas . Leia mais sobre como o planejador de consultas funciona nesta apresentação por Neil Conway (material avançado).No PostgreSQL, uma função sempre é executada automaticamente dentro de uma única transação . Tudo isso dá certo ou nada. Se ocorrer uma exceção, tudo será revertido. Mas há tratamento de erros ...
É também por isso que as funções não são exatamente "procedimentos armazenados" (mesmo que esse termo seja usado algumas vezes de maneira enganosa). Alguns comandos gostam
VACUUM
,CREATE INDEX CONCURRENTLY
ouCREATE DATABASE
não podem ser executados dentro de um bloco de transação, portanto, não são permitidos em funções. (Ainda não nos procedimentos SQL, a partir do Postgres 11. Isso pode ser adicionado posteriormente.)Eu escrevi milhares de funções plpgsql ao longo dos anos.
fonte
Alguns DO's:
fonte
De um modo geral, mover a lógica do aplicativo para o banco de dados significa que é mais rápido - afinal, ele estará mais próximo dos dados.
Acredito (mas não tenho 100% de certeza) que as funções da linguagem SQL sejam mais rápidas do que aquelas que usam outras linguagens, porque não requerem alternância de contexto. A desvantagem é que nenhuma lógica processual é permitida.
O PL / pgSQL é o mais completo e completo de recursos das linguagens incorporadas - mas, para desempenho, C pode ser usado (embora apenas beneficie funções computacionalmente intensivas)
fonte
Você pode fazer coisas muito interessantes usando as funções definidas pelo usuário (UDF) no postgresql. Por exemplo, existem dezenas de idiomas possíveis que você pode usar. O construído em pl / sql e pl / pgsql são capazes e confiáveis e usam um método sandbox para impedir que os usuários façam algo terrivelmente perigoso. As UDFs escritas em C oferecem a você o melhor em desempenho e potência, uma vez que são executadas no mesmo contexto que o próprio banco de dados. No entanto, é como brincar com fogo, porque mesmo pequenos erros podem causar grandes problemas, com falhas de back-end ou dados corrompidos. As linguagens custome pl, como pl / R, pl / ruby, pl / perl, etc., fornecem a capacidade de gravar as camadas de banco de dados e de aplicativo nos mesmos idiomas. Isso pode ser útil, pois significa que você não precisa ensinar um programador perl java ou pl / pgsql etc para escrever um UDF.
Por fim, existe a linguagem pl / proxy . Essa linguagem UDF permite executar seu aplicativo em dezenas ou mais servidores backgresql de back-end para fins de dimensionamento. Foi desenvolvido pelo pessoal do Skype e basicamente permite uma solução de escala horizontal para pessoas pobres. É surpreendentemente fácil escrever também.
Agora, quanto ao problema de desempenho. Esta é uma área cinza. Você está escrevendo um aplicativo para uma pessoa? Ou para 1.000? ou por 10.000.000? A maneira como você cria seu aplicativo e usa UDFs dependerá muito de como você está tentando escalar. Se você está escrevendo para milhares e milhares de usuários, a principal coisa que você quer fazer é reduzir a carga no banco de dados, tanto quanto possível. UDFs que reduzem a quantidade de dados que estão sendo movidos e retornados ao banco de dados ajudarão a reduzir a carga de E / S. No entanto, se eles começarem a aumentar a carga da CPU, eles podem ser um problema. De um modo geral, reduzir a carga de E / S é a primeira prioridade e garantir que os UDFs sejam eficientes para não sobrecarregar sua CPU é o próximo.
fonte