Postgres: "ERREUR: le plan mis en cache ne doit pas changer le type de résultat"

115

Cette exception est lancée par le serveur PostgreSQL 8.3.7 à mon application. Quelqu'un sait-il ce que signifie cette erreur et ce que je peux y faire?

ERROR:  cached plan must not change result type
STATEMENT:  select code,is_deprecated from country where code=$1
Jin Kim
la source
Pouvez-vous s'il vous plaît partager la version exacte de PostreSQL? 8.3.X?

Réponses:

190

J'ai compris ce qui causait cette erreur.

Mon application a ouvert une connexion à la base de données et préparé une instruction SELECT pour exécution.

Pendant ce temps, un autre script modifiait la table de la base de données, changeant le type de données de l'une des colonnes renvoyées dans l'instruction SELECT ci-dessus.

J'ai résolu ce problème en redémarrant l'application après la modification de la table de base de données. Cela réinitialise la connexion à la base de données, permettant à l'instruction préparée de s'exécuter sans erreur.

Jin Kim
la source
4
J'ai eu ceci sur PostgreSQL 9.0.4, avec Ruby on Rails 3.1-pre5. Il semble que cela devrait être géré automatiquement par ActiveRecord, non?
docwhat
3
Ouais, j'espère qu'ActiveRecord finira par s'en occuper. Je crois qu'appeler MyModel.reset_column_information corrigera les choses à court terme si vous voulez éviter de redémarrer.
Grant Hutchins
1
J'ai perdu une heure à comprendre ce qui n'allait pas. Votre réponse m'a sauvé!
Sri Harsha Kappala
3
Savez-vous qu'une solution ne nécessite pas le redémarrage de toutes les applications ou du serveur postgres? Peut-être existe-t-il une solution pour effacer manuellement le plan mis en cache lorsque l'erreur se produit?
Jacek Gzel
1
J'ai eu le même problème sur Postgres 10 lors de l'exécution des tests JUnit pour l'application spring + jpa. Message d'exception: org.postgresql.util.PSQLException: ERROR: cached plan must not change result type. Et tous les tests fonctionnent comme un charme, mais seulement Repository.findById(). Je ne change pas le schéma dans mes tests, mais j'utilise @FlywayTestpour préparer une base de données d'initialisation de test pour chaque test. Si je supprime l' @FlywayTestannotation, cela fonctionne bien.
Binakot
25

J'ajoute cette réponse pour quiconque atterrit ici en recherchant sur Google ERROR: cached plan must not change result type en essayant de résoudre le problème dans le contexte d'une application Java / JDBC.

J'ai pu reproduire l'erreur de manière fiable en exécutant des mises à niveau de schéma (c'est-à-dire des instructions DDL) pendant que mon application principale qui utilisait la base de données était en cours d'exécution. Si l'application interrogeait une table qui avait été modifiée par la mise à niveau du schéma (c'est-à-dire que l'application exécutait des requêtes avant et après la mise à niveau sur une table modifiée) - le pilote postgres renverrait cette erreur car apparemment, il met en cache certains détails du schéma.

Vous pouvez éviter le problème en configurant votre pgjdbcpilote avecautosave=conservative . Avec cette option, le pilote pourra vider tous les détails qu'il met en cache et vous ne devriez pas avoir à faire rebondir votre serveur ou à vider votre pool de connexions ou toute autre solution de contournement que vous avez trouvée.

Reproduit sur Postgres 9.6 (AWS RDS) et mes premiers tests semblent indiquer que le problème est complètement résolu avec cette option.

Documentation: https://jdbc.postgresql.org/documentation/head/connect.html#connection-parameters

Vous pouvez consulter le pgjdbc numéro 451 de Github pour plus de détails et l'historique du problème.


Les utilisateurs de JRuby ActiveRecords voient ceci: https://github.com/jruby/activerecord-jdbc-adapter/blob/master/lib/arjdbc/postgresql/connection_methods.rb#L60


Remarque sur les performances:

Selon les problèmes de performances signalés dans le lien ci-dessus, vous devez effectuer des tests de performance / charge / trempage de votre application avant de l'activer à l'aveugle.

En effectuant des tests de performances sur ma propre application exécutée sur une Postgres 10instance AWS RDS , l'activation du conservativeparamètre entraîne une utilisation supplémentaire du processeur sur le serveur de base de données. Ce n'était pas grand-chose cependant, je ne pouvais même voir la autosavefonctionnalité apparaître comme utilisant une quantité mesurable de CPU après avoir réglé chaque requête que mon test de charge utilisait et commencé à pousser le test de charge dur.

Dépouillé
la source
7
Pourquoi n'est-ce pas la valeur par défaut?
cdmckay
1
Fonctionne comme annoncé. Mes tests simples n'ont montré aucun impact sur les performances.
Samuli Pahaoja le
1
comment le configurer avec le pilote Ruby Postgres?
Hrishi
@Hrishi Votre commentaire m'a fait réaliser que la question d'origine ne spécifiait pas réellement Java (parce que je l'ai trouvé en traitant le problème dans un contexte Java). Je dirais que vous voudrez peut-être publier une toute nouvelle question à la recherche explicite d'une solution dans un contexte Ruby.
Shorn
@cdmckay Parce que c'était une nouvelle fonctionnalité introduite dans le pilote autour de la période de temps de la version 9.4-ish. Pour ma part, je serais très malheureux si une nouvelle version du pgjdbc cassait mon application car elle était activée par défaut, une nouvelle fonctionnalité non éprouvée dégradant les performances dont je n'avais pas besoin. (Cela dit, ceci est maintenant une nouvelle entrée sur ma liste de contrôle "Toujours faire cela lors de la création d'une nouvelle application").
Shorn
0

Pour nous, nous étions confrontés à un problème similaire. Notre application fonctionne sur plusieurs schémas. Chaque fois que nous faisions des changements de schéma, ce problème commençait à se produire.

La configuration du paramètre prepareThreshold = 0 dans le paramètre JDBC désactive la mise en cache des instructions au niveau de la base de données. Cela a résolu le problème pour nous.

irscomp
la source