Postgres: `не удалось выполнить поиск в кэше для ограничения 34055`

#postgresql #constraints #oid

#postgresql #ограничения #oid

Вопрос:

У меня есть OID, который генерирует кортеж, который, очевидно, недействителен.

Это ошибка, которую я получаю при попытке удалить таблицу в psql после некоторого set VERBOSITY verbose :

 delete from my_table where my_column = 'some_value';
ERROR:  XX000: cache lookup failed for constraint 34055
LOCATION:  ri_LoadConstraintInfo, ri_triggers.c:2832
  

Это то, что я нашел в другом месте.

 2827             :     /*
2828             :      * Fetch the pg_constraint row so we can fill in the entry.
2829             :      */
2830         548 :     tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
2831         548 :     if (!HeapTupleIsValid(tup)) /* should not happen */
2832           0 :         elog(ERROR, "cache lookup failed for constraint %u", constraintOid);
2833         548 :     conForm = (Form_pg_constraint) GETSTRUCT(tup);
2834             : 
2835         548 :     if (conForm->contype != CONSTRAINT_FOREIGN) /* should not happen */
2836           0 :         elog(ERROR, "constraint %u is not a foreign key constraint",
  

Я прочитал, что это означает, что на OID ссылаются в других местах. Где находятся эти другие места и кто-нибудь знает, как я могу очистить что-то подобное?

Мне действительно нравится /* should not happen */ комментарий к строке 2831.

Ответ №1:

Я бы сказал, что это означает, что у вас поврежден каталог.

Ограничения внешнего ключа внутренне реализованы в виде триггеров. Когда срабатывает этот триггер, он пытается найти ограничение, которое ему принадлежит. Похоже, в вашем случае это не удается, и это вызывает ошибку.

Вы можете убедиться сами:

 SELECT tgtype, tgisinternal, tgconstraint
   FROM pg_trigger
   WHERE tgrelid = 'my_table'::regclass;

┌────────┬──────────────┬──────────────┐
│ tgtype │ tgisinternal │ tgconstraint │
├────────┼──────────────┼──────────────┤
│      5 │ t            │        34055 │
│     17 │ t            │        34055 │
└────────┴──────────────┴──────────────┘
(2 rows)
  

Теперь попробуйте найти это ограничение:

 SELECT conname
   FROM pg_constraint
   WHERE oid = 34055;

┌─────────┐
│ conname │
├─────────┤
└─────────┘
(0 rows)
  

Чтобы восстановиться после такого повреждения, вам следует восстановить последнюю исправную резервную копию.

Вы можете попытаться спасти свои данные, используя pg_dumpall для сброса запущенного кластера PostgreSQL, создать новый кластер и восстановить дамп там. Если вам повезет, теперь у вас есть хорошая копия вашего кластера, и вы можете ее использовать. Если дамп или восстановление завершаются неудачей из-за несоответствий данных, вам придется использовать более продвинутые методы.

Как всегда в случае повреждения данных, лучше всего сначала остановить кластер с помощью

 pg_ctl stop -m immediate
  

и сделайте физическую резервную копию каталога данных. Таким образом, у вас есть копия, если ваша операция восстановления еще больше повредит данным.