Postgres: „BŁĄD: plan w pamięci podręcznej nie może zmieniać typu wyniku”


115

Ten wyjątek jest generowany przez serwer PostgreSQL 8.3.7 do mojej aplikacji. Czy ktoś wie, co oznacza ten błąd i co mogę z tym zrobić?

ERROR:  cached plan must not change result type
STATEMENT:  select code,is_deprecated from country where code=$1

Czy możesz udostępnić dokładną wersję PostreSQL? 8.3.X?

Odpowiedzi:


190

Dowiedziałem się, co powoduje ten błąd.

Moja aplikacja otworzyła połączenie z bazą danych i przygotowała instrukcję SELECT do wykonania.

W międzyczasie inny skrypt modyfikował tabelę bazy danych, zmieniając typ danych jednej z kolumn zwracanych w powyższej instrukcji SELECT.

Rozwiązałem ten problem, ponownie uruchamiając aplikację po zmodyfikowaniu tabeli bazy danych. Spowoduje to zresetowanie połączenia z bazą danych, umożliwiając wykonanie przygotowanej instrukcji bez błędów.


4
Mam to na PostgreSQL 9.0.4, z Ruby on Rails 3.1-pre5. Wygląda na to, że powinno to być obsługiwane automatycznie przez ActiveRecord, nie?
docwhat

3
Tak, mam nadzieję, że ActiveRecord w końcu się tym zajmie. Uważam, że wywołanie MyModel.reset_column_information naprawi rzeczy w krótkim okresie, jeśli chcesz uniknąć ponownego uruchamiania.
Grant Hutchins,

1
Straciłem godzinę, zastanawiając się, co poszło nie tak. Twoja odpowiedź mnie uratowała!
Sri Harsha Kappala

3
Czy wiesz, że jakieś rozwiązanie nie wymaga restartowania całej aplikacji lub serwera postgres? Może jest jakieś rozwiązanie, aby ręcznie wyczyścić buforowany plan, gdy wystąpi błąd?
Jacek Gzel

1
Mam ten sam problem na Postgres 10 podczas uruchamiania testów JUnit dla aplikacji spring + jpa. Komunikat wyjątku: org.postgresql.util.PSQLException: ERROR: cached plan must not change result type. Wszystkie testy działają jak urok, ale tylko Repository.findById(). Nie zmieniam schematu w moich testach, ale używam @FlywayTestdo przygotowania testowej bazy danych init dla każdego testu. Jeśli usunę @FlywayTestadnotację, działa dobrze.
Binakot

25

Dodaję tę odpowiedź dla każdego, kto tu ląduje, szukając w Google ERROR: cached plan must not change result typepodczas próby rozwiązania problemu w kontekście aplikacji Java / JDBC.

Udało mi się niezawodnie odtworzyć błąd, uruchamiając aktualizacje schematu (tj. Instrukcje DDL), gdy działała moja aplikacja zaplecza, która korzystała z bazy danych. Jeśli aplikacja wysyłała zapytania do tabeli, która została zmieniona przez aktualizację schematu (tj. Aplikacja wykonywała zapytania przed i po aktualizacji w zmienionej tabeli) - sterownik postgres zwróciłby ten błąd, ponieważ najwyraźniej buforuje niektóre szczegóły schematu.

Możesz uniknąć problemu, konfigurując pgjdbcsterownik z rozszerzeniem autosave=conservative. Dzięki tej opcji sterownik będzie mógł opróżnić wszystkie szczegóły, które przechowuje w pamięci podręcznej, i nie powinieneś być zmuszony do odbijania serwera, opróżniania puli połączeń lub jakiegokolwiek innego obejścia, które możesz wymyślić.

Reprodukowane na Postgres 9.6 (AWS RDS) i moje wstępne testy wydają się wskazywać, że problem został całkowicie rozwiązany dzięki tej opcji.

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

Więcej szczegółów i historię problemu można znaleźć w pgjdbc numerze 451 na Githubie .


Użytkownicy JRuby ActiveRecords widzą to: https://github.com/jruby/activerecord-jdbc-adapter/blob/master/lib/arjdbc/postgresql/connection_methods.rb#L60


Uwaga dotycząca wydajności:

Zgodnie z zgłoszonymi problemami z wydajnością w powyższym linku - przed ślepym włączeniem tej aplikacji należy przeprowadzić testy wydajności / obciążenia / nasiąknięcia.

Podczas testowania wydajności mojej własnej aplikacji działającej na wystąpieniu AWS RDS Postgres 10, włączenie tego conservativeustawienia powoduje dodatkowe zużycie procesora na serwerze bazy danych. Nie było to jednak dużo, mogłem nawet zobaczyć, jak autosavefunkcjonalność pojawia się jako użycie mierzalnej ilości procesora po dostrojeniu każdego zapytania, z którego korzystał mój test obciążenia i zacząłem mocno przesuwać test obciążenia.


7
Dlaczego nie jest to ustawienie domyślne?
cdmckay

1
Działa zgodnie z reklamą. Moje proste testy nie wykazały żadnego wpływu na wydajność.
Samuli Pahaoja,

1
jak skonfigurować go ze sterownikiem Ruby Postgres?
Hrishi

@Hrishi Twój komentarz uświadomił mi, że pierwotne pytanie tak naprawdę nie określało języka Java (ponieważ znalazłem je podczas rozwiązywania problemu w kontekście Java). Powiedziałbym, że możesz chcieć opublikować zupełnie nowe pytanie, wyraźnie szukając rozwiązania w kontekście Rubiego.
Shorn

@cdmckay Ponieważ była to nowa funkcjonalność wprowadzona do sterownika w ramach czasowych wersji 9.4. Po pierwsze, byłbym bardzo niezadowolony, gdyby jakaś nowa wersja pgjdbc zepsuła moją aplikację, ponieważ domyślnie włączała nową, nie sprawdzoną, obniżającą wydajność funkcjonalność, której nie potrzebowałem. (To powiedziawszy, jest to teraz nowy wpis na mojej liście kontrolnej „rób to zawsze podczas tworzenia nowej aplikacji”).
Shorn

0

Dla nas stanęliśmy przed podobnym problemem. Nasza aplikacja działa na wielu schematach. Za każdym razem, gdy robiliśmy zmiany schematu, ten problem zaczął się pojawiać.

Ustawienie parametru readyThreshold = 0 w parametrze JDBC wyłącza buforowanie instrukcji na poziomie bazy danych. To rozwiązało to za nas.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.