pg_restore错误:角色XXX不存在。

106

尝试将一个系统中的数据库复制到另一个系统。涉及的版本是9.5.0(源)和9.5.2(目标)。

源数据库名称为foodb,所有者为pgdba,目标数据库名称将被命名为foodb_dev,所有者为pgdev

所有命令都在托管副本的目标系统上运行。

pg_dump命令为:

    pg_dump -f schema_backup.dump --no-owner -Fc -U pgdba -h $PROD_DB_HOSTNAME -p $PROD_DB_PORT -d foodb -s --clean;

这段代码可以无误地运行。

对应的pg_restore命令是:

    pg_restore --no-owner --if-exists -1 -c -U pgdev -d foodb_dev schema_backup.dump

会抛出错误的代码:

pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 3969; 0 0 ACL public pgdba
pg_restore: [archiver (db)] could not execute query: ERROR:  role "pgdba" does not exist
Command was: REVOKE ALL ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM pgdba;
GRANT ALL ON SCHEMA public TO pgdba;
GRANT ...

如果我以纯文本格式(-Fp)生成转储文件,我会看到它包括多个条目,例如:

REVOKE ALL ON TABLE dump_thread FROM PUBLIC;
REVOKE ALL ON TABLE dump_thread FROM pgdba;
GRANT ALL ON TABLE dump_thread TO pgdba;
GRANT SELECT ON TABLE dump_thread TO readonly;

尝试为用户pgdba设置权限,但目标系统上不存在该用户,而只有用户pgdev,因此会出现pg_restore的错误。

在源数据库中,例如dump_thread表的权限:

# \dp+ dump_thread
Access privileges
-[ RECORD 1 ]-----+--------------------
Schema            | public
Name              | dump_thread
Type              | table
Access privileges | pgdba=arwdDxt/pgdba+
                  | readonly=r/pgdba
Column privileges |
Policies          |

一个快速的解决方案是在目标集群上简单地添加一个名为pgdba的用户,然后完成操作。

但是,在转储数据之前,--no-owner选项不应该负责排除拥有者特定命令吗?

5个回答

114

我意识到 --no-owner-x 不同。我将 -x 添加到所有的 pg_dump 命令中,这意味着:

-x, --no-privileges          do not dump privileges (grant/revoke)

实际上,这将排除掉转储中有问题的GRANT/REVOKE命令。问题解决了。


9
有没有办法在不使用-x选项的情况下恢复数据库?在我的情况下,备份是由别人提供给我的,因此我无法使用-x选项修改它。 - Sanjay Salunkhe
119
pg_restore --no-privileges --no-owner ... allows you to specify not to include ownership or privileges at the time of restore whether or not those privileges and ownerships were included in the pg_dump - user1448319
6
这应该是答案。在恢复时跳过所有者/特权比在备份时跳过更好。 - mivk
9
去除所有权和特权是否存在任何未预见的不利影响? - L.Youl
2
@l-youl:对于生产数据库,我相信会有的。最好在恢复之前重新创建角色,就像Hartmut建议的那样。在这种情况下,OP很可能不关心,因为他们只是为了测试或查看数据而进行恢复。 - Paul
显示剩余6条评论

8

恢复数据库,请运行以下命令:

pg_restore -x --no-owner -d db_name backup.dump

3

使用以下命令恢复数据库备份:

pg_restore --no-privileges --no-owner -h localhost -p <DB_Port> -U <DB_User> -d <DB_Name>-1 <DB_Backup_Path>

使用标记--no-privileges 可以防止恢复访问权限(授权/撤销命令),同时

--no-owner 可以防止设置对象的所有权与原始数据库匹配。


0
如果您已将数据库导出为“自定义”文件类型,则可以使用以下命令。 pg_restore -c -U <DATABASE_USERNAME> -d <DATABASE_NAME> -v <FILE_PATH_IN_STRING> -W 确保已创建数据库,并指定正确的用户名和文件路径名。

0
你的“快速解决方案”是正确的:
一个快速的解决方案是在目标集群上简单地添加一个用户pgdba,然后就可以完成了。
在你的情况下,这可能不是一个问题,但是如果你在恢复数据库时忽略所有者和权限,会导致信息丢失。在某些情况下,信息丢失可能不是一个问题,但在其他情况下,比如如果你有一个正在使用一个或多个角色访问数据库的应用程序,并且你需要保留这些信息,那么遵循这里的一些建议,比如使用“--no-privileges/--no-owner”进行恢复可能会破坏你的应用程序。
PostgreSQL将用户和角色信息存储在层次结构的较高级别,即服务器级别,而不是数据库级别。当你使用pg_dump备份单个数据库时,它不会备份用户和角色的创建,因为这些信息存储在服务器级别。
因此,如果你想从备份中恢复数据库,你需要首先创建或恢复相关的用户和角色。
如果你可以访问原始服务器设置,还可以使用pg_dumpall来导出/备份这些信息。如果你有很多用户和角色,这可能是最好的选择。
在其他情况下,就像你所说的那样,设置可能就像一个拥有特定数据库的单个用户那样简单,那么你就不需要担心这个问题,你只需要创建一个单个用户,并将该用户指定为你创建的新数据库的所有者,然后你就可以运行pg_restore,它不会抛出这些错误。
对于上面的问题,没有一个适用于所有情况的答案,但是因为你的错误信息只涉及一个用户,我强烈怀疑你的设置是一个简单的设置,只有一个用户。在这种情况下,你只需要在服务器级别上创建这个用户,然后创建数据库并将该用户指定为所有者,然后你就可以运行pg_restore。
如果为时已晚,你总是可以事后修复这些问题;在简单的情况下,你可能只需要类似以下的操作:
ALTER DATABASE db_name OWNER TO new_owner_name;

再次强调,在特定情况下,您可能不需要这样做,但通常情况下,更改角色/所有者往往会导致一些问题,尤其是当有外部应用程序或脚本可能使用此角色连接到数据库时,这样做并不好。最好养成良好的习惯,学会在不丢失信息的情况下进行操作,因为即使现在可以正常工作,下次可能就不行了。
此外,在像Stack Overflow这样的网站上,总会有人遇到类似但稍有不同的情况。在这种情况下,涉及信息丢失的“hack”解决方案会误导他们并浪费他们的时间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接