Postgres: “ERROR: o plano em cache não deve mudar o tipo de resultado”

115

Esta exceção está sendo lançada pelo servidor PostgreSQL 8.3.7 para meu aplicativo. Alguém sabe o que significa esse erro e o que posso fazer a respeito?

ERROR:  cached plan must not change result type
STATEMENT:  select code,is_deprecated from country where code=$1
Jin Kim
fonte
Você pode compartilhar a versão exata do PostreSQL? 8.3.X?

Respostas:

190

Eu descobri o que estava causando esse erro.

Meu aplicativo abriu uma conexão de banco de dados e preparou uma instrução SELECT para execução.

Enquanto isso, outro script estava modificando a tabela do banco de dados, alterando o tipo de dados de uma das colunas retornadas na instrução SELECT acima.

Resolvi isso reiniciando o aplicativo depois que a tabela do banco de dados foi modificada. Isso reinicializa a conexão do banco de dados, permitindo que a instrução preparada seja executada sem erros.

Jin Kim
fonte
4
Consegui isso no PostgreSQL 9.0.4, com Ruby on Rails 3.1-pre5. Parece que isso deve ser tratado automaticamente pelo ActiveRecord, não?
docwhat
3
Sim, espero que o ActiveRecord acabe por cuidar disso. Acredito que chamar MyModel.reset_column_information corrigirá as coisas a curto prazo se você quiser evitar a reinicialização.
Grant Hutchins de
1
Perdi uma hora tentando descobrir o que deu errado. Sua resposta me salvou!
Sri Harsha Kappala
3
Você conhece alguma solução que não exija a reinicialização de todos os aplicativos ou do servidor postgres? Talvez haja alguma solução para limpar manualmente o plano em cache quando ocorrer o erro?
Jacek Gzel
1
Eu tive o mesmo problema no Postgres 10 ao executar testes JUnit para o aplicativo spring + jpa. Mensagem de exceção: org.postgresql.util.PSQLException: ERROR: cached plan must not change result type. E todos os testes funcionam perfeitamente, mas apenas Repository.findById(). Não mudo o esquema em meus testes, mas estou usando @FlywayTestpara preparar um banco de dados de inicialização de teste para cada teste. Se eu remover a @FlywayTestanotação, funciona bem.
Binakot
25

Estou adicionando esta resposta para quem chega aqui pesquisando ERROR: cached plan must not change result typeno Google ao tentar resolver o problema no contexto de um aplicativo Java / JDBC.

Consegui reproduzir o erro de forma confiável executando atualizações de esquema (ou seja, instruções DDL) enquanto meu aplicativo de back-end que usava o banco de dados estava em execução. Se o aplicativo estava consultando uma tabela que foi alterada pela atualização do esquema (ou seja, o aplicativo executou consultas antes e depois da atualização em uma tabela alterada) - o driver postgres retornaria este erro porque aparentemente faz o cache de alguns detalhes do esquema.

Você pode evitar o problema configurando seu pgjdbcdriver com autosave=conservative. Com esta opção, o driver será capaz de liberar quaisquer detalhes que esteja armazenando em cache e você não terá que devolver seu servidor ou liberar seu pool de conexão ou qualquer solução alternativa que possa ter surgido.

Reproduzido no Postgres 9.6 (AWS RDS) e meu teste inicial parece indicar que o problema foi completamente resolvido com esta opção.

Documentação: https://jdbc.postgresql.org/documentation/head/connect.html#connection-parameters

Você pode consultar a pgjdbc edição 451 do Github para obter mais detalhes e o histórico do problema.


Os usuários do JRuby ActiveRecords veem isso: https://github.com/jruby/activerecord-jdbc-adapter/blob/master/lib/arjdbc/postgresql/connection_methods.rb#L60


Nota sobre o desempenho:

De acordo com os problemas de desempenho relatados no link acima - você deve fazer alguns testes de desempenho / carga / absorção do seu aplicativo antes de ligar cegamente.

Ao fazer o teste de desempenho em meu próprio aplicativo em execução em uma Postgres 10instância AWS RDS , habilitar a conservativeconfiguração resulta em uso extra de CPU no servidor de banco de dados. Não foi muito, porém, eu só pude ver a autosavefuncionalidade aparecer como usando uma quantidade mensurável de CPU depois de ajustar cada consulta que meu teste de carga estava usando e começar a forçar o teste de carga.

Tosado
fonte
7
Por que este não é o padrão?
cdmckay
1
Funciona conforme anunciado. Meus testes simples não mostraram nenhum impacto no desempenho.
Samuli Pahaoja de
1
como configurá-lo com o driver Ruby Postgres?
Hrishi
@Hrishi Seu comentário me fez perceber que a pergunta original não especificava Java (porque eu a encontrei ao lidar com o problema em um contexto Java). Eu diria que você pode querer postar uma questão totalmente nova, procurando explicitamente por uma solução em um contexto Ruby.
Corte em
@cdmckay Porque foi uma nova funcionalidade introduzida no driver por volta do período da versão 9.4-ish. Eu, pelo menos, ficaria muito infeliz se alguma nova versão do pgjdbc quebrasse meu aplicativo porque ele habilitava para o padrão uma nova funcionalidade de degradação de desempenho não comprovada que eu não precisava. (Dito isto, esta é agora uma nova entrada na minha lista de verificação "sempre faça isso ao criar um novo aplicativo").
Corte em
0

Para nós, estávamos enfrentando um problema semelhante. Nosso aplicativo funciona em vários esquemas. Sempre que estávamos fazendo alterações de esquema, esse problema começou a ocorrer.

Configurar o parâmetro prepareThreshold = 0 dentro do parâmetro JDBC desativa o cache de instrução no nível do banco de dados. Isso resolveu para nós.

irscomp
fonte