PostgreSQL - отключение ограничений - PullRequest
42 голосов
/ 21 апреля 2010

У меня есть таблица с примерно 5 миллионами строк, в которой есть ограничение fk, ссылающееся на первичный ключ другой таблицы (также около 5 миллионов строк).

Мне нужно удалить около 75000 строк из обеих таблиц. Я знаю, что если я попытаюсь сделать это с включенным ограничением fk, это займет недопустимое количество времени.

Исходя из опыта Oracle, моей первой мыслью было отключить ограничение, выполнить удаление и затем снова включить ограничение. PostGres позволяет мне отключать триггеры ограничений, если я являюсь суперпользователем (я не являюсь пользователем, но я вхожу в систему как пользователь, владеющий / создавший объекты), но это не совсем то, чего я хочу.

Другой вариант - сбросить ограничение и затем восстановить его. Я обеспокоен тем, что восстановление ограничения займет много времени, учитывая размер моих таблиц.

Есть мысли?

edit: после поощрения Билли я попытался удалить, не меняя никаких ограничений, и это заняло более 10 минут. Однако я обнаружил, что таблица, из которой я пытаюсь удалить, имеет собственный ссылочный внешний ключ ... дублированный (& не проиндексированный).

Окончательное обновление - я удалил собственный ссылочный внешний ключ, сделал свое удаление и добавил его обратно. Билли прав со всех сторон, но, к сожалению, я не могу принять его комментарий в качестве ответа!

Ответы [ 6 ]

48 голосов
/ 21 апреля 2010

За предыдущие комментарии это должно быть проблемой. Тем не менее, есть команда, которая может быть тем, что вы ищете - она ​​установит ограничения на отложенные, поэтому они проверяются на COMMIT, а не на каждое удаление. Если вы делаете только одно большое УДАЛЕНИЕ из всех строк, это не будет иметь значения, но если вы делаете это по частям, это будет.

SET CONSTRAINTS ALL DEFERRED

- это то, что вы ищете в этом случае. Обратите внимание, что ограничения должны быть помечены как DEFERRABLE, прежде чем они могут быть отложены. Например:

ALTER TABLE table_name
  ADD CONSTRAINT constraint_uk UNIQUE(column_1, column_2)
  DEFERRABLE INITIALLY IMMEDIATE;

Затем ограничение может быть отложено в транзакции или функции следующим образом:

CREATE OR REPLACE FUNCTION f() RETURNS void AS
$BODY$
BEGIN
  SET CONSTRAINTS ALL DEFERRED;

  -- Code that temporarily violates the constraint...
  -- UPDATE table_name ...
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
15 голосов
/ 24 февраля 2017

Для меня сработало отключение по очереди TRIGGERS тех таблиц, которые будут задействованы в операции DELETE.

ALTER TABLE reference DISABLE TRIGGER ALL;
DELETE FROM reference WHERE refered_id > 1;
ALTER TABLE reference ENABLE TRIGGER ALL;

Решение работает в версии 9.3.16. В моем случае время увеличилось с 45 минут до 14 секунд на выполнение DELETE операций.

Как указано в разделе комментариев @amphetamachine, для выполнения этой задачи вам понадобятся admin привилегии для таблиц.

4 голосов
/ 26 сентября 2016

(Этот ответ предполагает, что вы намерены удалить все строки этих таблиц, а не только выборку.)

Я тоже должен был это сделать, но как часть набора тестов. Я нашел ответ, предложенный в другом месте на SO . Используйте TRUNCATE TABLE следующим образом:

TRUNCATE TABLE <list-of-table-names> [RESTART IDENTITY] [CASCADE];

Следующее быстро удаляет все строки из таблиц table1, table2 и table3, при условии, что нет ссылок на строки этих таблиц из не перечисленных таблиц:

TRUNCATE TABLE table1, table2, table3;

Пока ссылки находятся между перечисленными таблицами, PostgreSQL удалит все строки, не заботясь о ссылочной целостности. Если таблица, отличная от перечисленных, ссылается на строку одной из этих таблиц, запрос не будет выполнен.

Однако вы можете квалифицировать запрос, чтобы он также обрезал все таблицы со ссылками на перечисленные таблицы (хотя я не пробовал этого):

TRUNCATE TABLE table1, table2, table3 CASCADE;

По умолчанию последовательности этих таблиц не перезапускают нумерацию. Новые строки будут продолжены со следующего номера последовательности. Для перезапуска порядковой нумерации:

TRUNCATE TABLE table1, table2, table3 RESTART IDENTITY;
3 голосов
/ 15 января 2018

Если вы попробуете DISABLE TRIGGER ALL и получите сообщение об ошибке типа permission denied: "RI_ConstraintTrigger_a_16428" is a system trigger (я получил это на Amazon RDS), попробуйте следующее:

set session_replication_role to replica;

Если это удастся, все триггеры, лежащие в основе ограничений таблицы, будут отключены. Теперь вам нужно убедиться, что ваши изменения оставляют БД в согласованном состоянии!

Затем, когда вы закончите, включите триггеры и ограничения для вашего сеанса с:

set session_replication_role to default;
1 голос
/ 30 октября 2018

Мой PostgreSQL - 9.6.8.

set session_replication_role to replica;

работает для меня, но мне нужно разрешение.

Я вхожу в PSQL с суперпользователем.

sudo -u postgres psql

Тогдаподключиться к моей базе данных

\c myDB

и выполнить:

set session_replication_role to replica;

Теперь я могу удалить из таблицы ограничение

0 голосов
/ 06 апреля 2015

Отключить все ограничения таблицы

ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName

- Включить все ограничения таблицы

ALTER TABLE TableName CHECK CONSTRAINT ConstraintName
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...