web-dev-qa-db-ja.com

pg_restore:[アーカイバ(db)]はクエリを実行できませんでした:エラー:スキーマ "public"はすでに存在します

Pg_dump/pg_restoreを使用してPostgreSQLデータベースをバックアップおよび復元していますが、pg_restoreからいくつかのエラーメッセージ(およびゼロ以外の終了ステータス)が返されます。私は非常に単純な基本ケース(以下に概説)を試しましたが、それでもこれらのエラーが発生しました:

 pg_restore:[archiver(db)] TOCの処理中にエラーが発生しました:
 pg_restore:[archiver(db)] TOCエントリ5からのエラー。 2615 2200 SCHEMA public postgres 
 pg_restore:[archiver(db)] couldn run query:ERROR:schema "public" already exists 
 Command was:CREATE SCHEMA public; 

再現する手順:

  1. 新しい、Vanilla Ubuntu 14.04ディストリビューションをインストールします(私はVagrantを このVagrantボックス で使用しています)。
  2. PostgreSQL 9.3をインストールし、任意のLinuxユーザーからのPostgreSQLユーザー「postgres」としてローカル接続を許可するように設定します。
  3. テストデータベースを作成します。私はただやっています:

     vagrant @ vagrant-ubuntu-trusty-64:〜$ psql --username = postgres postgres 
     psql(9.3.5)
    ヘルプとして「help」と入力してください。
     
     postgres =#create database mydb; 
     CREATE DATABASE 
     postgres =#\ q 
     vagrant @ vagrant-ubuntu-trusty-64:〜$ psql- -username = postgres mydb 
     psql(9.3.5)
    ヘルプを表示するには「help」と入力します。
     
     mydb =#create table data(entry bigint); 
     CREATE TABLE 
     mydb =#insert into data values(1); 
     INSERT 0 1 
     mydb =#insert into data values(2); 
     INSERT 0 1 
     mydb =#insert into data values(3); 
     INSERT 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)] TOCエントリ5からのエラー。 2615 2200 SCHEMA public postgres 
 pg_restore:[archiver(db)] couldn run query:ERROR:schema "public" already exists 
 Command was:CREATE SCHEMA public; 
 
 
 
警告:復元時に無視されたエラー:1 

このコマンドをプログラムで実行していて、終了ステータスを使用して復元が失敗したかどうかを判断する必要があるため、これを無視することはできません。最初、この問題の原因はデータベースをパブリック(デフォルトのスキーマ)に配置したためかと思いました。データが復元される前にpg_restoreによって--createオプションの結果としてpublicが作成されると推論しました(おそらくテーブルがそこにあるため、スキーマも作成しようとする可能性があります)。テーブルを別のスキーマで使用する上記の手順では、結果は同じで、エラーメッセージは同じでした。

私は何か間違ったことをしていますか?このエラーが表示されるのはなぜですか?

20
KSletmoe

エラーは無害ですが、それを取り除くには、次のように、この復元を2つのコマンドに分割する必要があると思います。

dropdb -U postgres mydb && \
 pg_restore --create --dbname=postgres --username=postgres pg_backup.dump

Pg_restoreの--cleanオプションは多くのようには見えませんが、実際には重要な問題を引き起こします。

バージョン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...

個々のオブジェクトごとにDROPはなく、最初はDROP DATABASEのみです。 --createを使用しない場合、これは逆になります。

とにかく、template0からpublicを作成するとすでにインポートされているため、このシーケンスは既存のmydbスキーマのエラーを発生させます(これは通常、テンプレートデータベースのポイントです)。

このケースがpg_restoreによって自動的に処理されない理由がわかりません。管理者がtemplate0をカスタマイズしたり、publicの目的を変更したりすると、予期しない副作用が発生する可能性があります。

17
Daniel Vérité

私の場合、理由は、postgresql-contribバージョン11.2のpg_restoreを使用して、pg_dump 9.6で作成されたダンプをPostgreSQLクラスター9.6に復元していたためです。

pg_restoreを9.6にダウングレードした後、このschema "public" already existsエラーはなくなり、復元プロセスは以前と同様に機能しました。

7
Lu Liu

復元にはパブリックスキーマが含まれ、データベースも作成されます。したがって、データベースを作成した後にスキーマを削除して、復元でエラーなしでスキーマを作成できるようにします。

注:以下では、-h -U -pがデフォルトで、PGPASSWORDまたは.pgpassが設定されていると想定しています。

    psql << XENDX
    drop database if exists DB_NAME;
    create database DB_NAME;
    /c DB_NAME;
    drop schema if exists public;
    create schema public;
    XENX

    pg_restore -d DB_NAME FILE_CREATED_WITH_pg_dump
1
DaJudge

私はそれを解決しました:

の中に db.sqlファイル

drop database if exists DB_name;
create database DB_name;
drop schema if exists public;
create schema public;
\q

その後

PGPASSWOD=DB_pass psql -U DB_user -h 127.0.0.1 < db.sql

その後

PGPASSWOD=DB_pass pg_restore -h 127.0.0.1 \ 
    -U DB_user -d DB_name --create --no-acl --no-owner DB_dump_FILE

私のpg_restoreバージョンは11.6です

0
user9869932