Postgres: "ERROR: el plan almacenado en caché no debe cambiar el tipo de resultado"

114

El servidor PostgreSQL 8.3.7 lanza esta excepción a mi aplicación. ¿Alguien sabe qué significa este error y qué puedo hacer al respecto?

ERROR:  cached plan must not change result type
STATEMENT:  select code,is_deprecated from country where code=$1
Jin Kim
fuente
¿Puede compartir la versión exacta de PostreSQL? 8.3.X?

Respuestas:

188

Descubrí qué estaba causando este error.

Mi aplicación abrió una conexión de base de datos y preparó una instrucción SELECT para su ejecución.

Mientras tanto, otro script estaba modificando la tabla de la base de datos, cambiando el tipo de datos de una de las columnas que se devuelven en la declaración SELECT anterior.

Resolví esto reiniciando la aplicación después de que se modificó la tabla de la base de datos. Esto restableció la conexión de la base de datos, permitiendo que la declaración preparada se ejecute sin errores.

Jin Kim
fuente
3
Obtuve esto en PostgreSQL 9.0.4, con Ruby on Rails 3.1-pre5. Parece que esto debería ser manejado automáticamente por ActiveRecord, ¿no?
docwhat
3
Sí, espero que ActiveRecord eventualmente se encargue de esto. Creo que llamar a MyModel.reset_column_information solucionará las cosas a corto plazo si desea evitar reiniciar.
Grant Hutchins
1
Perdí una hora averiguando qué salió mal. ¡Tu respuesta me salvó!
Sri Harsha Kappala
3
¿Conoce alguna solución que no requiera reiniciar todas las aplicaciones o el servidor postgres? ¿Quizás haya alguna solución para borrar manualmente el plan almacenado en caché cuando se produce el error?
Jacek Gzel
1
Obtuve el mismo problema en Postgres 10 mientras ejecutaba pruebas JUnit para la aplicación spring + jpa. Mensaje de excepción: org.postgresql.util.PSQLException: ERROR: cached plan must not change result type. Y todas las pruebas funcionan como un encanto, pero solo Repository.findById(). No cambio el esquema en mis pruebas, pero lo estoy usando @FlywayTestpara preparar una base de datos de inicio de prueba para cada prueba. Si elimino la @FlywayTestanotación, funciona bien.
Binakot
25

Estoy agregando esta respuesta para cualquiera que aterrice aquí ERROR: cached plan must not change result typebuscando en Google cuando intente resolver el problema en el contexto de una aplicación Java / JDBC.

Pude reproducir de manera confiable el error ejecutando actualizaciones de esquema (es decir, declaraciones DDL) mientras se ejecutaba mi aplicación de back-end que usaba la base de datos. Si la aplicación consultaba una tabla que había sido modificada por la actualización del esquema (es decir, la aplicación ejecutó consultas antes y después de la actualización en una tabla modificada), el controlador de postgres devolvería este error porque aparentemente almacena en caché algunos detalles del esquema.

Puede evitar el problema configurando su pgjdbccontrolador con autosave=conservative. Con esta opción, el controlador podrá vaciar cualquier detalle que esté almacenando en caché y no debería tener que hacer rebotar su servidor o vaciar su grupo de conexiones o cualquier solución alternativa que se le haya ocurrido.

Reproducido en Postgres 9.6 (AWS RDS) y mi prueba inicial parece indicar que el problema está completamente resuelto con esta opción.

Documentación: https://jdbc.postgresql.org/documentation/head/connect.html#connection-parameters

Puede consultar el pgjdbc número 451 de Github para obtener más detalles y el historial del problema.


Los usuarios de JRuby ActiveRecords ven esto: https://github.com/jruby/activerecord-jdbc-adapter/blob/master/lib/arjdbc/postgresql/connection_methods.rb#L60


Nota sobre el rendimiento:

De acuerdo con los problemas de rendimiento informados en el enlace anterior, debe realizar algunas pruebas de rendimiento / carga / remojo de su aplicación antes de activarla a ciegas.

Al realizar pruebas de rendimiento en mi propia aplicación que se ejecuta en una Postgres 10instancia de AWS RDS , habilitar la conservativeconfiguración da como resultado un uso adicional de la CPU en el servidor de la base de datos. Sin embargo, no fue mucho, solo pude ver que la autosavefuncionalidad se mostraba usando una cantidad medible de CPU después de haber ajustado cada consulta que estaba usando mi prueba de carga y comencé a presionar la prueba de carga con fuerza.

Esquilado
fuente
7
¿Por qué no es este el valor predeterminado?
cdmckay
1
Funciona como se anuncia. Mis pruebas simples no mostraron ningún impacto en el rendimiento.
Samuli Pahaoja
1
¿Cómo configurarlo con el controlador Ruby Postgres?
Hrishi
@Hrishi Tu comentario me hizo darme cuenta de que la pregunta original en realidad no especificaba Java (porque lo encontré al tratar el problema en un contexto de Java). Yo diría que es posible que desee publicar una pregunta completamente nueva buscando explícitamente una solución en un contexto de Ruby.
Shorn
@cdmckay Porque se introdujo una nueva funcionalidad en el controlador alrededor del período de tiempo de la versión 9.4. Por mi parte, sería muy infeliz si una nueva versión de pgjdbc rompiera mi aplicación porque habilitaba de forma predeterminada una funcionalidad nueva, no probada y que degrada el rendimiento que no necesitaba. (Dicho esto, esta es ahora una nueva entrada en mi lista de verificación "siempre haga esto al crear una nueva aplicación").
Shorn
0

Para nosotros, nos enfrentábamos a un problema similar. Nuestra aplicación funciona en múltiples esquemas. Siempre que estábamos haciendo cambios de esquema, este problema comenzaba a surgir.

La configuración del parámetro prepareThreshold = 0 dentro del parámetro JDBC inhabilita el almacenamiento en caché de declaraciones a nivel de la base de datos. Esto nos solucionó.

irscomp
fuente