pg_restore: [archiver (db)] не смог выполнить запрос: ОШИБКА: схема «public» уже существует

17

Я использую pg_dump / pg_restore для резервного копирования и восстановления базы данных PostgreSQL, но получаю некоторые сообщения об ошибках (и ненулевой статус выхода) из pg_restore. Я попробовал очень простой базовый вариант (обрисованный в общих чертах ниже), но все еще получил эти ошибки:

pg_restore: [archiver (db)] Ошибка при обработке текста:
pg_restore: [archiver (db)] Ошибка записи TOC 5; 2615 2200 SCHEMA публичные постгрес
pg_restore: [archiver (db)] не смог выполнить запрос: ОШИБКА: схема "public" уже существует
    Команда была: СОЗДАТЬ СХЕМУ ПУБЛИЧНОЙ;

Действия по воспроизведению:

  1. Установите свежий, ванильный дистрибутив Ubuntu 14.04 (я использую Vagrant с этой коробкой Vagrant ).
  2. Установите PostgreSQL 9.3, сконфигурируйте так, чтобы локальные подключения были разрешены как пользователь PostgreSQL «postgres» от любого пользователя Linux.
  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

Данные восстанавливаются, но команда pg_restore на шаге 6 завершается со статусом 1и показывает следующий вывод:

pg_restore: [archiver (db)] Ошибка при обработке текста:
pg_restore: [archiver (db)] Ошибка записи TOC 5; 2615 2200 SCHEMA публичные постгрес
pg_restore: [archiver (db)] не смог выполнить запрос: ОШИБКА: схема "public" уже существует
    Команда была: СОЗДАТЬ СХЕМУ ПУБЛИЧНОЙ;



ВНИМАНИЕ: при восстановлении ошибки игнорируются: 1

Я не могу просто проигнорировать это, потому что я запускаю эту команду программно и мне нужно использовать состояние выхода, чтобы определить, было ли восстановление неудачным или нет. Первоначально я задавался вопросом, была ли эта проблема, потому что я сделал свою базу данных общедоступной (схема по умолчанию). Я рассуждал, что public будет создан в результате --createопции pg_restore до восстановления данных (что, возможно, может попытаться создать и эту схему, поскольку именно там находится моя таблица), но когда я попытался выполнить описанные выше шаги с моей таблицей в другой схеме результаты были одинаковыми, а сообщения об ошибках были идентичными.

Я делаю что-то неправильно? Почему я вижу эту ошибку?

KSletmoe
источник

Ответы:

16

Ошибка безвредна, но, чтобы избавиться от нее, я думаю, что вам нужно разбить это восстановление на две команды, например:

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

--cleanВариант в pg_restore не выглядит как много , но на самом деле вызывает нетривиальные проблемы.

Для версий до 9.1

Комбинация --createи --cleanв параметрах pg_restore была ошибкой в ​​старых версиях PG (до 9.1). Между ними есть некоторое противоречие (цитируем 9.1 manpage):

--clean Очистить (удалить) объекты базы данных перед их воссозданием

и

--create Создать базу данных перед ее восстановлением.

Потому что какой смысл очищать в новой базе данных?

Начиная с версии 9.2

Комбинация теперь принята, и доктор говорит это (цитируя 9.3 manpage):

--clean Очистить (удалить) объекты базы данных перед их воссозданием. (Это может генерировать некоторые безобидные сообщения об ошибках, если какие-либо объекты не присутствуют в целевой базе данных.)

--create Создать базу данных перед ее восстановлением. Если также указан параметр --clean, удалите и заново создайте целевую базу данных перед подключением к ней.

Теперь, когда оба вместе приводят к такой последовательности во время восстановления:

DROP DATABASE mydb;
...
CREATE DATABASE mydb WITH TEMPLATE = template0... [other options]
...
CREATE SCHEMA public;
...
CREATE TABLE...

Нет DROPдля каждого отдельного объекта, только DROP DATABASEв начале. Если не использовать --createэто было бы наоборот.

В любом случае, эта последовательность вызывает ошибку publicуже существующей схемы, потому что создание mydbиз template0нее уже импортировало (что является нормой, это точка базы данных шаблонов).

Я не уверен, почему этот случай не обрабатывается автоматически pg_restore. Возможно, это приведет к нежелательным побочным эффектам, когда администратор решит настроить template0и / или изменить назначение public, даже если мы не должны этого делать.

Даниэль Верите
источник
Я использую 9.6, и указание --createбез cleanне решает проблему.
Церин
7

В моем случае причина была в том, что я использовал pg_restoreверсию 11.2 postgresql-contrib для восстановления дампа, сделанного pg_dump9.6, в кластер PostgreSQL 9.6.

После того, как я понизил мою pg_restoreспину до 9.6, эта schema "public" already existsошибка исчезла, и процесс восстановления работал как прежде.

Лу Лю
источник
Но вы восстановили дамп с помощью pg_restore 9.6 в базу данных postgres 11.2?
Мариано Руис
@MarianoRuiz Я думаю, мой оригинальный ответ ясен: «Я использовал pg_restore из postgresql-contrib версии 11.2 для восстановления дампа, сделанного pg_dump 9.6, в кластер PostgreSQL 9.6». Итак, на ваш вопрос: нет, я не сделал. Мой pg_restore был 11.2, в то время как pg кластер был 9.6
Лу Лю