PostgreSQL - отключение ограничений

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

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

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

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

Любые мысли?

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

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

Ответ 1

В предыдущих комментариях это должно быть проблемой. Тем не менее, есть команда, которая может быть тем, к чему вы хотите, - это заставит ограничения отложить, чтобы они были проверены на COMMIT, а не на каждом удалении. Если вы делаете только один большой DELETE из всех строк, это не будет иметь никакого значения, но если вы делаете это на куски, это будет.

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;

Ответ 2

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

Я тоже должен был это сделать, но как часть тестового набора. Я нашел ответ, предложенный в другом месте на 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

То, что работало для меня, состояло в том, чтобы отключить один за другим 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.

Ответ 4

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

ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName

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

ALTER TABLE TableName CHECK CONSTRAINT ConstraintName