Я получил дамп моей базы данных PostgreSQL с:
pg_dump -U user-name -d db-name -f dumpfile
который я затем продолжаю восстанавливать в другой базе данных:
psql X -U postgres -d db-name-b -f dumpfile
Моя проблема заключается в том, что база данных содержит ссылочные ограничения, проверки и триггеры, и некоторые из них (проверки могут показаться особенно) дают сбой во время восстановления, так как информация не загружается в том порядке, в котором эти проверки будут выполнены. Например, вставка строки в таблицу может быть связана с функцией, CHECK
вызывающей plpgsql
функцию, которая проверяет, выполняется ли условие в какой-либо другой несвязанной таблице. Если эта последняя таблица не загружена psql
до первой, возникает ошибка.
Ниже приведен SSCCE, который создает такую базу данных, которая после сброса pg_dump
не может быть восстановлена:
CREATE OR REPLACE FUNCTION fail_if_b_empty () RETURNS BOOLEAN AS $$
SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;
CREATE TABLE IF NOT EXISTS a (
i INTEGER NOT NULL
);
INSERT INTO a(i) VALUES (0),(1);
CREATE TABLE IF NOT EXISTS b (
i INTEGER NOT NULL
);
INSERT INTO b(i) VALUES (0);
ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty());
Есть ли способ отключить (из командной строки) все такие ограничения во время восстановления дампа и включить их снова после этого? Я использую PostgreSQL 9.1.
источник
-X
и-d
вариантов дляpg_dump
.pg_dump
создает дамп, который можно восстановить в пустой БД.CHECK
ограничении, то все гарантии аннулируются, потому что это официально не поддерживается, просто допускается. Но объявлениеCHECK
ограниченияNOT VALID
заставило меня работать во всех отношениях. Могут быть угловые случаи, которых я никогда не трогал ...Ответы:
Итак, вы ищите другие таблицы в
CHECK
ограничении .CHECK
ограничения должны запускатьIMMUTABLE
проверки. То, что проходит ОК для строки за один раз, должно пройти ОК в любое время. Вот какCHECK
ограничения определены в стандарте SQL. Это также причина этого ограничения ( согласно документации ):Теперь выражениям в
CHECK
ограничениях разрешено использовать функции, даже пользовательские функции. Они должны быть ограниченыIMMUTABLE
функциями, но Postgres в настоящее время не применяет это. Согласно этому связанному обсуждению pgsql-хакеров , одной из причин является разрешение ссылок на текущее время, что неIMMUTABLE
является естественным.Но вы просматриваете строки другой таблицы, что полностью нарушает то, как
CHECK
ограничения должны работать. Я не удивлен, чтоpg_dump
не может обеспечить это.Переместите чек из другой таблицы в триггер (это правильный инструмент), и он должен работать с современными версиями Postgres.
PostgreSQL 9.2 или более поздняя версия
Хотя вышеприведенное справедливо для любой версии Postgres, в Postgres 9.2 было добавлено несколько инструментов, которые помогут вам в вашей ситуации:
опция pg_dump
--exclude-table-data
Простым решением было бы сбросить базу данных без данных для таблицы-нарушителя с помощью:
Затем добавьте только данные для этой таблицы в конце дампа с помощью:
Но могут возникнуть сложности с другими ограничениями на той же таблице. Есть еще лучшее решение :
NOT VALID
Есть
NOT VALID
модификатор для ограничений. Доступно только для ограничения FK в v9.1, но это было расширено доCHECK
ограничений в 9.2. По документации:Простой файл дампа postgres состоит из трех «разделов»:
pre_data
data
post-data
В Postgres 9.2 также была добавлена возможность раздельного копирования разделов
-- section=sectionname
, но это не помогло решить проблему.Вот где это становится интересным. По документации:
Жирный акцент мой.
Вы можете изменить нарушающее
CHECK
ограничение наNOT VALID
, которое перемещает ограничение вpost-data
раздел. Оставьте и воссоздайте:Это должно решить вашу проблему. Вы даже можете оставить ограничение в этом состоянии , поскольку оно лучше отражает то, что оно фактически делает: проверяет новые строки, но не дает никаких гарантий для существующих данных. В
NOT VALID
проверочном ограничении нет ничего плохого . Если вы предпочитаете, вы можете проверить это позже:Но затем вы вернетесь к статус-кво анте.
источник
pg_dump
добавляет триггеры в конец файла дампа, в то время как он создаетCHECK
s как частьCREATE TABLE
команды. Таким образом, восстановление могло бы также быть успешным для контрольного случая, еслиpg_dump
инструмент использовал другой подход. Я не понимаю, почему мой DDL в порядке, если я использую триггеры, но не в порядке, если я использую проверки, поскольку в обоих случаях реализована точно такая же логика (вы можете увидеть версию сценария с использованием триггеров в моем собственном ответе).pg_dump
должны генерировать разные DDL для проверочных ограничений (например, добавляя их все в конце), вы должны опубликовать это в списке рассылки Postgres как запрос на расширение. Но я согласен с Эрвином в том, что вы неправильно используете проверочные ограничения для того, для чего они не были предназначены. Поэтому я не ожидаю, что этот запрос на изменение будет реализован в ближайшем будущем. Кстати, ваш SSCCE будет лучше смоделирован с использованием внешнего ключа между двумя таблицами.Похоже, это связано с тем, как
pg_dump
создается дамп. Глядя на реальный дамп, я увидел, что вCHECK
файле дампов присутствовало ограничение с использованием синтаксиса, который является частьюCREATE TABLE
команды:Это создает сбой при восстановлении базы данных, поскольку проверка выполняется до того, как в таблице
a
или таблицеb
есть какие-либо данные. Однако, если файл дампа отредактирован иCHECK
добавлен с использованием следующего синтаксиса, в конце файла дампа:... то в реставрации проблем нет.
Точно такая же логика может быть реализована с использованием,
TRIGGER
как в следующем скрипте:В этом случае, однако,
pg_dump
создается (по умолчанию) триггер в конце файла дампа (а не вCREATE TABLE
операторе, как в случае проверки), и поэтому восстановление завершается успешно.источник