导入备份错误:“无法创建唯一索引”

您好,

我正在尝试将一个论坛迁移到新服务器。两个服务器都运行最新版本的 Discourse Docker。通过命令行导入备份时,出现以下错误:

ERROR:  could not create unique index "index_incoming_referers_on_path_and_incoming_domain_id"
DETAIL:  Key (path, incoming_domain_id)=(/search/, 418) is duplicated.
EXCEPTION: psql failed: DETAIL:  Key (path, incoming_domain_id)=(/search/, 418) is duplicated.

这似乎与以下链接中的错误相同或相似:

但是,在我的案例中,重复的记录是 /search/ 路径,而不是上面链接线程中提到的 /m/search

我已经连接到旧服务器上的容器(./launcher enter app),并在 Rails 控制台(rails c)中尝试使用以下命令搜索重复的记录:

IncomingReferer.where(path: "/search")

IncomingReferer.where("path LIKE '%/search%'")

然而,这会显示数百条记录。我该如何找出哪些记录是重复的,以及如何安全地删除它们并重建?论坛在旧服务器上目前运行正常,我们只是需要迁移到新硬件。

您尝试过使用管理 GUI 吗?

不,我以为通过 GUI 导入会调用相同的导入流程?我现在就试试。

我怀疑这意味着您的索引已损坏。您正在运行哪个版本的 Postgres?

类似如下命令:

cd /var/discourse
cat shared/standalone/postgres_data/PG*

(我有点记不清 Postgres 的具体文件名了。)

您可以在这里搜索“postgres corrupt index”,找到我曾撰写的一个主题,其中介绍了如何追踪并删除那些损坏的记录。

您基本上可以尝试重建该索引,删除它报错的记录,然后再次尝试重建索引,直到成功重建为止。

刚刚尝试通过 GUI 导入,结果完全一样:

旧服务器上没有名为 PG_VERSION 的文件,如何确定其运行的版本?我今天已将 docket 安装更新到最新版本。

新服务器(刚完成引导)运行的是 Postgres V13

cat shared/standalone/postgres_data/PG_VERSION
13

是否有推荐的执行此操作的具体步骤?

我曾有一个包含一些提示的主题,但现在看不到了。自 PostgreSQL 12 升级以来已接近一年。

  reindex index index_incoming_referers_on_path_and_incoming_domain_id;

以及

 ActiveRecord::Base.connection.execute('reindex index index_incoming_referers_on_path_and_incoming_domain_id;')

是尝试重建索引的方法。这会报错,然后您可以删除出错的记录。您需要同时包含路径和 ID。

好的,我已经修复了。我执行了以下操作:

进入容器

./launcher enter app

连接到数据库

su postgres -c 'psql discourse'

尝试查找重复项

discourse=# select * from incoming_referers where path LIKE '%/search/' ORDER BY incoming_domain_id;
  id  |    path    | incoming_domain_id
------+------------+--------------------
 3339 | /search/   |                 33
 6257 | /search/   |                 91
 1567 | /search/   |                298
 1777 | /search/   |                341
 3010 | /search/   |                418
 6247 | /search/   |                418
 4293 | /search/   |                644
 2899 | /search/   |                653
 3447 | /search/   |                793
 3696 | /search/   |                852
 4395 | /a/search/ |               1050
 6968 | /search/   |               1305
 5634 | /search/   |               1387
 5834 | /search/   |               1437
 6519 | /search/   |               1637
 7127 | /search/   |               1787
 7280 | /search/   |               1827
(17 rows)

删除重复项

DELETE FROM incoming_referers WHERE path LIKE '%/search/' AND id IN (6247);

然后重建

discourse=# REINDEX SCHEMA CONCURRENTLY public;
WARNING:  cannot reindex invalid index "public.incoming_referers_pkey_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_incoming_referers_on_path_and_incoming_domain_id_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "pg_toast.pg_toast_20732_index_ccnew" concurrently, skipping
REINDEX

之后我再次进行了备份,将其复制到新服务器,并成功导入 :smiley:

如果备份过程能够检测重复项以避免任何问题就好了。我很幸运还能访问仍在运行的原始服务器。如果我在恢复冷备份,这可能会成为一个更大的问题。

非常感谢您的帮助。