У меня есть база данных на PostgreSQL 9.2, которая имеет основную схему с около 70 таблицами и переменное количество одинаково структурированных схем для каждого клиента по 30 таблиц в каждой. Клиентские схемы имеют внешние ключи, ссылающиеся на основную схему, а не наоборот.
Я только начал заполнять базу данных реальными данными, взятыми из предыдущей версии. Размер БД достиг примерно 1,5 ГБ (ожидается, что он увеличится до нескольких десятков ГБ в течение нескольких недель), когда мне пришлось выполнять массовое удаление в центральной таблице основной схемы. Все соответствующие внешние ключи отмечены на УДАЛЕННОМ КАСКАДЕ.
Неудивительно, что это займет много времени, но через 12 часов стало ясно, что мне лучше начать заново, сбросить БД и снова запустить миграцию. Но что, если мне нужно будет повторить эту операцию позже, когда БД жива и намного больше? Есть ли альтернативные, более быстрые методы?
Было бы намного быстрее, если бы я написал скрипт, который будет просматривать зависимые таблицы, начиная с таблицы, самой удаленной от центральной таблицы, удаляя таблицу зависимых строк за таблицей?
Важной деталью является то, что на некоторых таблицах есть триггеры.
источник
Ответы:
У меня была аналогичная проблема. Как оказалось, эти
ON DELETE CASCADE
триггеры немного замедлили процесс, потому что эти каскадные удаления были ужасно медленными.Я решил эту проблему, создав индексы для полей внешнего ключа в ссылочных таблицах, и у меня ушло от нескольких часов на удаление до нескольких секунд.
источник
ON DELETE CASCADE
)EXPLAIN (ANALYZE, BUFFERS)
запрос на удаление одной строки, и он должен показать вам, какие ограничения внешнего ключа потребовали больше всего времени (по крайней мере, для меня).PRIMARY
индекса, ноUNIQUE
индекс определенно недостаточно хорош для этой цели.У вас есть несколько вариантов. Лучший вариант - запустить пакетное удаление, чтобы триггеры не срабатывали. Отключите триггеры перед удалением, затем снова включите их. Это экономит вам очень много времени. Например:
Главный ключ здесь - вы хотите минимизировать глубину подзапросов. В этом случае вы можете настроить временные таблицы для хранения соответствующей информации, чтобы избежать глубоких подзапросов при удалении.
источник
Простой способ , чтобы решить эту проблему, чтобы запросить подробную синхронизацию с PostgreSQL:
EXPLAIN
. Для этого вам нужно найти как минимум один запрос, который выполняется, но занимает больше времени, чем ожидалось. Допустим, что эта строка будет выглядетьВместо того, чтобы действительно запустить эту команду, вы можете сделать
Откат в конце позволяет выполнить это без реального изменения базы данных, но вы все равно получите подробные данные о том, сколько времени потребовалось. После этого вы можете обнаружить, что какой-то триггер вызывает огромные задержки:
Значение
time
в мс (миллисекунде), поэтому проверка этого противопоказания заняла около 12,3 секунды. Вам нужно добавить новыйINDEX
над необходимыми столбцами, чтобы этот триггер мог быть эффективно вычислен. Для ссылок на внешний ключ столбец, который ссылается на другую таблицу, должен быть проиндексирован (т. Е. Исходный столбец, а не целевой столбец). PostgreSQL не создает автоматически такие индексы автоматически иDELETE
является единственным распространенным запросом, где вам действительно нужен этот индекс. В результате вы, возможно, накопили данные за годы, пока не дойдете до случая, когдаDELETE
слишком медленно из-за отсутствия индекса.После того, как вы зафиксировали производительность этого ограничения (или что-то еще, что заняло слишком много времени), повторите команду в
begin
/rollback
block, чтобы вы могли сравнить новое время выполнения с предыдущим. Продолжайте до тех пор, пока вы не будете довольны временем отклика на удаление одной строки (мне нужно было выполнить один запрос от 25,6 до 15 мс, просто добавив разные индексы). Затем вы можете продолжить полное удаление без каких-либо взломов.(Обратите внимание, что
EXPLAIN
нужен запрос, который может успешно завершиться. У меня когда-то была проблема, когда PostgreSQL слишком долго выяснял, что одно удаление будет нарушать ограничение внешнего ключа, и в этом случаеEXPLAIN
его нельзя использовать, поскольку он не будет генерировать синхронизацию для сбойного запросы. Я не знаю простой способ отладки проблем с производительностью в таком случае.)источник
Отключение триггеров может угрожать целостности БД и не может быть рекомендовано; однако если вы уверены, что ваша операция защищена от ограничений, вы можете отключить триггеры следующим образом:
SET session_replication_role = replica;
Запустите
DELETE
здесь.Чтобы восстановить триггеры, запустите:
SET session_replication_role = DEFAULT;
Источник здесь.
источник
Если у вас есть триггеры ON DELETE CASCADE, мы надеемся, что они присутствуют по какой-то причине и поэтому не должны быть отключены. Другой прием (все еще добавляющий ваши индексы), который работает для меня, заключается в создании функции удаления, которая вручную удаляет данные, начиная с таблиц в конце каскада, и работает в направлении основной таблицы. (Это то же самое, что и при наличии триггера ON DELETE RESTRICT)
В этом случае удалите данные в таблице, затем в таблице, затем в таблице.
источник