Postgres: `cache lookup failed for constraint 34055`

1N5*_*818 2 postgresql constraints oid

I'm have an OID that is generating a tuple that is evidently not valid.

This is the error I get when trying to delete a table in psql after some \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
Run Code Online (Sandbox Code Playgroud)

This is what I found elsewhere.

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",
Run Code Online (Sandbox Code Playgroud)

I read this means the OID is being referenced in other places. Where are these other places and does anyone know how I to clean something like this up?

I really like the /* should not happen */ comment on line 2831.

Lau*_*lbe 6

我想说这意味着您的目录已损坏。

外键约束在内部实现为触发器。当触发该触发器时,它将尝试查找属于它的约束。在您的情况下,这似乎失败了,并导致了错误。

您可以自己看到:

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

????????????????????????????????????????
? tgtype ? tgisinternal ? tgconstraint ?
????????????????????????????????????????
?      5 ? t            ?        34055 ?
?     17 ? t            ?        34055 ?
????????????????????????????????????????
(2 rows)
Run Code Online (Sandbox Code Playgroud)

现在尝试查找该约束:

SELECT conname
   FROM pg_constraint
   WHERE oid = 34055;

???????????
? conname ?
???????????
???????????
(0 rows)
Run Code Online (Sandbox Code Playgroud)

要从这种损坏中恢复,您应该还原最新的正常备份。

您可以尝试通过pg_dumpall转储正在运行的PostgreSQL集群,创建新集群并在此处还原转储来抢救数据。如果幸运的话,您现在可以很好地使用群集了,就可以使用它了。如果转储或还原由于数据不一致而失败,则必须使用更高级的方法。

与往常一样,在发生数据损坏的情况下,最好先使用

pg_ctl stop -m immediate
Run Code Online (Sandbox Code Playgroud)

并对数据目录进行物理备份。这样,如果您的补救操作进一步损坏了数据,则您将拥有一份副本。