1

你好 Slack Overflowvians。

所以我遇到了这个运行 8.3.11 的 PostgreSQL 服务器(是的,我知道),它处于锁定状态:

ERROR:  database is not accepting commands to avoid wraparound data loss in database "postgres"
HINT:  Stop the postmaster and use a standalone backend to vacuum that database.

autovacuum=on通常自动清理守护进程(但是由于这些损坏的数据库对象,该数据库的 XID 从未被重置。

以下是使用管理员用户在单用户模式下运行服务器时的输出片段:

SELECT oid, relname, age(relfrozenxid) FROM pg_class WHERE relkind = 't' ORDER BY age(relfrozenxid) DESC LIMIT 4;


    ----
     1: oid = "2421459"     (typeid = 26, len = 4, typmod = -1, byval = t)
     2: relname = "pg_toast_2421456"        (typeid = 19, len = 64, typmod = -1, byval = f)
     3: age = "2146484084"  (typeid = 23, len = 4, typmod = -1, byval = t)
    ----
     1: oid = "2421450"     (typeid = 26, len = 4, typmod = -1, byval = t)
     2: relname = "pg_toast_2421447"        (typeid = 19, len = 64, typmod = -1, byval = f)
     3: age = "2146484084"  (typeid = 23, len = 4, typmod = -1, byval = t)
    ----
     1: oid = "2421435"     (typeid = 26, len = 4, typmod = -1, byval = t)
     2: relname = "pg_toast_2421432"        (typeid = 19, len = 64, typmod = -1, byval = f)
     3: age = "2146484084"  (typeid = 23, len = 4, typmod = -1, byval = t)
    ----
     1: oid = "2421426"     (typeid = 26, len = 4, typmod = -1, byval = t)
     2: relname = "pg_toast_2421423"        (typeid = 19, len = 64, typmod = -1, byval = f)
     3: age = "2146484084"  (typeid = 23, len = 4, typmod = -1, byval = t)

请注意,此服务器上的年龄远高于vacuum_freeze_min_age(成功 VACUUM 后设置的值),因此它发出上述原始错误的原因。以上是在运行之后VACUUM FULL;所有其他表都很好。

SELECT relfilenode FROM pg_class WHERE oid=2421459;

因此,当我们查看磁盘时(使用上面每个表的 pg_class.relfilenode 值),toast 表的文件丢失了:

$ find /var/lib/pgsql/data/ -type f -name '2421426' | wc -l  # Bad toast
0

当我们在磁盘上查看 toast 的索引时

 SELECT relfilenode FROM pg_class WHERE (select reltoastidxid FROM pg_class WHERE oid=2421459)

$ find /var/lib/pgsql/data/ -type f -name '2421459' | wc -l  # Bad toast's index
0

然后我们试图找到与坏 toast 记录相关的表:

SELECT * FROM pg_class WHERE reltoastrelid=2421459;

上面的每个表格都有 0 个结果!没有用于VACUUM重置这些关系的 XID 的命令的表。

当我们检查 pg_depend 表并发现这些 TOAST 表没有引用时:

SELECT * FROM pg_depend WHERE refobjid IN(2421459,2421450,2421435,2421426)

问题

  1. 你能从 pg_class 表中删除坏的 TOAST 表和 TOAST 表索引吗(例如DELETE FROM pg_class where oid=2421459
  2. 我们还需要从其他表中删除关系吗?
  3. 我们可以只创建一个临时表并将其链接到 TOAST 的索引的 oid 吗?

上面 #3 的示例:

CREATE TABLE adoptedparent (colnameblah char(1));
UPDATE pg_class SET reltoastrelid=2421459 WHERE relname='adoptedparent';  
VACUUM FULL VERBOSE adoptedparent

编辑:

select txid_current()是 3094769499,所以这些表很久以前就损坏了。我们不需要恢复数据。我们在 Linux 2.6.18-238.el5 上运行 ext4 文件系统。我们检查了相关lost+found/目录,文件不存在。

4

1 回答 1

0

仅针对家庭观众,在这种特殊情况下,解决方案是直接编辑 pg_class。当然,将服务器更新到受支持的 Postgres 版本!

具体答案:

  1. 是的,您可以,尽管在大多数情况下最好创建一个空表,将 toast 关系附加到该表,添加 pg_depend 条目,然后删除该表。在这种情况下,这没有任何意义,因为确实没有其他对象依赖于这些吐司表。

    1. 通常 toast 表在 pg_index 中也有一个索引,在 pg_depend 中有条目。这些没有。

    2. 看上面。

于 2015-10-01T03:27:34.107 回答