pg_restore: [archiver (db)] 无法执行查询:错误:架构“public”已经存在

KSl*_*moe 33 postgresql backup restore

我正在使用 pg_dump / pg_restore 来备份和恢复 PostgreSQL 数据库,但是从 pg_restore 收到一些错误消息(和非零退出状态)。我尝试了一个超级简单的基本案例(如下所述),但仍然出现以下错误:

pg_restore: [archiver (db)] 处理 TOC 时出错:
pg_restore: [archiver (db)] 目录条目 5 中的错误;2615 2200 SCHEMA公共postgres
pg_restore: [archiver (db)] 无法执行查询:错误:架构“public”已经存在
    命令是:CREATE SCHEMA public;

重现步骤:

  1. 安装一个全新的、原版的 Ubuntu 14.04 发行版(我在这个 Vagrant box 中使用 Vagrant )。
  2. 安装 PostgreSQL 9.3,配置为允许任何 Linux 用户以 PostgreSQL 用户“postgres”的身份进行本地连接。
  3. 创建一个测试数据库。我只是在做:

    vagrant@vagrant-ubuntu-trusty-64:~$ psql --username=postgres postgres
    psql (9.3.5)
    输入“帮助”以获得帮助。
    
    postgres=# 创建数据库 mydb;
    创建数据库
    postgres=# \q
    vagrant@vagrant-ubuntu-trusty-64:~$ psql --username=postgres mydb
    psql (9.3.5)
    输入“帮助”以获得帮助。
    
    mydb=# 创建表数据(条目 bigint);
    创建表
    mydb=# 插入数据值(1);
    插入 0 1
    mydb=# 插入数据值(2);
    插入 0 1
    mydb=# 插入数据值(3);
    插入 0 1
    mydb=# \q
    
  4. 像这样创建数据库的备份:

    PGPASSWORD="postgres" pg_dump --dbname=mydb --username=postgres --format=custom > pg_backup.dump
  5. 从 mydb 中的数据表中删除一些行,以便我们能够判断是否成功恢复了数据。

  6. 使用以下命令恢复数据库:

    PGPASSWORD="postgres" pg_restore --clean --create --dbname=postgres --username=postgres pg_backup.dump

数据已恢复,但步骤 6 中的 pg_restore 命令以状态退出1并显示以下输出:

pg_restore: [archiver (db)] 处理 TOC 时出错:
pg_restore: [archiver (db)] 目录条目 5 中的错误;2615 2200 SCHEMA公共postgres
pg_restore: [archiver (db)] 无法执行查询:错误:架构“public”已经存在
    命令是:CREATE SCHEMA public;



警告:还原时忽略的错误:1

我不能忽略这一点,因为我正在以编程方式运行此命令,并且需要使用退出状态来确定还原是否失败。最初,我想知道这个问题是否是因为我将我的数据库公开(默认模式)。我推断--create在恢复数据之前 pg_restore的选项会创建 public (可以想象也可以尝试创建该模式,因为那是我的表所在的位置),但是当我对我的表尝试上述步骤时在不同的模式中,结果是相同的,错误消息是相同的。

难道我做错了什么?为什么我看到这个错误?

Dan*_*ité 25

该错误是无害的,但要摆脱它,我认为您需要将此还原分解为两个命令,如下所示:

dropdb -U postgres mydb && \
 pg_restore --create --dbname=postgres --username=postgres pg_backup.dump
Run Code Online (Sandbox Code Playgroud)

--cleanpg_restore 中的选项看起来并不多,但实际上引发了不小的问题。

对于版本高达 9.1

pg_restore 选项中的--create和组合--clean曾经是旧 PG 版本(最高 9.1)中的错误。之间确实存在一些矛盾(引用 9.1 联机帮助页):

--clean 在重新创建之前清理(删除)数据库对象

--create 在恢复之前创建数据库。

因为在一个全新的数据库内部进行清理有什么意义?

从 9.2 版本开始

该组合现在已被接受,并且文档这样说(引用 9.3 联机帮助页):

--clean 在重新创建之前清理(删除)数据库对象。(如果目标数据库中不存在任何对象,这可能会生成一些无害的错误消息。)

--create 在恢复之前创建数据库。如果还指定了 --clean,则在连接之前删除并重新创建目标数据库。

现在将两者放在一起会导致恢复期间的这种序列:

DROP DATABASE mydb;
...
CREATE DATABASE mydb WITH TEMPLATE = template0... [other options]
...
CREATE SCHEMA public;
...
CREATE TABLE...
Run Code Online (Sandbox Code Playgroud)

DROP每个单独的对象都没有,只有一个DROP DATABASE开头。如果不使用--create这将是相反的。

无论如何,这个序列会引发public模式已经存在的错误,因为创建mydbtemplate0已经导入了它(这是正常的,这是模板数据库的重点)。

我不确定为什么这种情况不是由pg_restore. 当管理员决定自定义template0和/或更改 的目的时public,这可能会导致不良副作用,即使我们不应该这样做。

  • 我使用的是 9.6,指定不带 `clean` 的 `--create` 不能解决问题。 (2认同)

小智 9

就我而言,原因是我使用pg_restorepostgresql-contrib 版本 11.2 将pg_dump9.6 生成的转储恢复到 PostgreSQL 集群 9.6。

在我降级pg_restore到 9.6 后,这个schema "public" already exists错误消失了,恢复过程和以前一样工作。


小智 7

就我而言,我能够通过先运行CREATE DATABASE target_db;然后运行pg_restore来解决这个问题--schema=public -d target_db。这假设您只需要公共模式,但我认为这是很常见的情况。