Пакетное удаление в Postgres с помощью курсора - PullRequest
0 голосов
/ 23 октября 2018

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

Шаги, которые у меня в голове:

  • объявить курсор, открыть его
  • извлекать записи в курсор, где будет установлен фильтр на дату
  • передавать контролируемые записи, например, 5000 / транзакция для удаления цикла
  • , пока начальная выборка не будет завершена
  • выйти из цикла и закрыть курсор

Это имеет смысл?

1 Ответ

0 голосов
/ 27 октября 2018

Просто DELETE.Забудьте курсор.

Если ваша таблица огромная и вы удаляете большой процент строк, нет смысла делать это в пакетах.И даже тогда нет смысла.Единственные причины, по которым я могу придумать, - разрешить VACUUM удалять мертвые кортежи раньше, что может помочь в особых случаях.Или чтобы избежать конфликта блокировок (возможны взаимоблокировки?), Но возникает вопрос, почему строки, которые должны быть удалены, должны быть заблокированы одновременными транзакциями.

Блокировки на строку для этого,Нет конфликта с одновременными INSERT или UPDATE до различными строками.(Если у вас есть ОБНОВЛЕНИЯ, нацеленные на одни и те же строки, у вас есть большая проблема.) И писатели не блокируют читателей в любом случае на Postgres.

Вы можете создайте курсор SQL с параметром WITH HOLD , а затем используйте его с DELETE ... WHERE CURRENT OF в отдельных транзакциях.Но вам придется добавить FOR UPDATE, блокируя все затронутые строки в любом случае.Редко имеет смысл, за исключением случаев, когда вы хотите быстро заблокировать все затронутые строки, но по-прежнему что-то делать с ними перед удалением, и могут быть более разумные способы ...

Может иметь смысл разделить большую UPDATE - вотдельные транзакции - так, чтобы мертвые кортежи можно было повторно использовать в обновлениях HOT (после ручного запуска VACUUM или автоматического включения вакуума).Но это вряд ли относится к DELETE операциям, которые не используют пространство повторно.Кроме того, DELETE намного быстрее, чем UPDATE.

В маловероятном событии , которое вам все еще нужно сделать в пакетном режиме, все равно не используйте курсор.Используйте что-то вроде:

WITH cte AS (
   SELECT id                 -- your PK
   FROM   tbl
   WHERE  date < $something  -- your condition
   -- ORDER BY ???           -- optional, see below
   LIMIT  50000
   FOR    UPDATE             -- SKIP LOCKED ?
   )
DELETE FROM tbl
USING  cte
WHERE  tbl.id = cte.id;

Повторяйте до тех пор, пока строки не будут найдены.

Если ваши данные (в основном) физически отсортированы определенным образом, они могут заплатить за заказ строк соответственно (в кавычках)ORDER BY).ORDER BY накладывает свою цену, но каждый DELETE может иметь доступ к гораздо меньшему количеству страниц данных с кластеризованными строками и быстрее работать таким образом.Зависит от варианта использования;если ORDER BY может использовать индекс, прогноз лучше.

См .:

...