15.4. Segurança da paralelização #

15.4.1. Marcação de paralelização para funções e agregações

O planejador classifica as operações envolvidas em uma consulta como paralela segura, paralela restrita ou paralela insegura. Uma operação paralela segura é aquela que não entra em conflito com o uso de consulta paralelizada. Uma operação paralela restrita é aquela que não pode ser executada em um processo trabalhador paralelo, mas pode ser executada no líder enquanto a consulta paralelizada está em uso. Portanto, operações paralelas restritas nunca podem ocorrer abaixo de um nó Gather ou Gather Merge, mas podem ocorrer em outro lugar em um plano que contenha tal nó. Uma operação paralela insegura é aquela que não pode ser executada enquanto a consulta paralelizada está em uso, nem mesmo no líder. Quando uma consulta contém algo que não é seguro fazer em paralelo, a consulta paralelizada é completamente desativada para esta consulta.

As seguintes operações são sempre restritas ao paralelismo:

15.4.1. Marcação de paralelização para funções e agregações #

O planejador não pode determinar automaticamente se uma função ou agregação definida pelo usuário é paralela segura, paralela restrita ou paralela insegura, porque isto exigiria a previsão de todas as operações que a função poderia executar. Em geral, isto equivale ao Problema da Parada, portanto, é impossível. Mesmo para funções simples onde poderia ser feito, não é tentado, porque seria caro e propenso a erros. Em vez disso, todas as funções definidas pelo usuário são consideradas paralelas inseguras, a menos que estejam marcadas de outra forma. Quando é usado CREATE FUNCTION ou ALTER FUNCTION, as marcações podem ser definidas especificando PARALLEL SAFE, PARALLEL RESTRICTED ou PARALLEL UNSAFE, conforme seja apropriado. Quando é usado CREATE AGGREGATE, a opção PARALLEL pode ser especificada como SAFE, RESTRICTED ou UNSAFE, conforme seja apropriado.

Funções e agregações devem ser marcadas como PARALLEL UNSAFE se escreverem no banco de dados, alterarem o estado da transação (exceto usando uma subtransação para recuperação de erros), acessarem sequências ou fizerem alterações persistentes nas configurações. De forma semelhante, as funções devem ser marcadas como PARALLEL RESTRICTED se acessarem tabelas temporárias, estado da conexão do cliente, cursores, instruções preparadas ou qualquer estado de processo do servidor local que o sistema não possa sincronizar entre diferentes processos trabalhadores. Por exemplo, setseed e random têm paralelização restrita por este último motivo.

Em geral, se uma função é marcada como segura quando é restrita ou insegura, ou se é marcada como restrita quando, na verdade, não é segura, a função pode gerar erros, ou produzir respostas erradas, quando usada em uma consulta paralelizada. As funções da linguagem C podem, em teoria, exibir um comportamento totalmente indefinido se marcadas erroneamente, uma vez não haver como o sistema possa se proteger contra um código C arbitrário, mas geralmente o resultado não será pior que para qualquer outra função. Em caso de dúvida, provavelmente é melhor rotular as funções como UNSAFE.

Se uma função executada em um processo trabalhador paralelo adquirir bloqueios que não são mantidos pelo líder, por exemplo, consultando uma tabela não referenciada na consulta, estes bloqueios serão liberados na saída do processo trabalhador, e não no final da transação. Se for escrita uma função que faz isto, e esta diferença de comportamento for importante, esta função deve ser marcada como PARALLEL RESTRICTED para garantir que seja executada apenas no líder.

Note que o planejador de consulta não considera adiar a avaliação de funções ou agregações paralelas restritas envolvidas na consulta para obter um plano superior. Assim, por exemplo, se a cláusula WHERE aplicada a uma determinada tabela for paralela restrita, o planejador de consulta não vai considerar a realização de uma varredura desta tabela na parte paralela do plano. Em alguns casos, seria possível (e talvez até eficiente) incluir a varredura desta tabela na parte paralela da consulta, e adiar a avaliação da cláusula WHERE para ocorrer acima do nó Gather. Entretanto, o planejador não faz isto.