Как удалить фиксированное количество строк с сортировкой в ​​PostgreSQL?

Я пытаюсь перенести некоторые старые MySQL-запросы в PostgreSQL, но у меня возникают проблемы с этим:

DELETE FROM logtable ORDER BY timestamp LIMIT 10;

PostgreSQL не разрешает упорядочение или ограничения в синтаксисе удаления, а таблица не имеет первичного ключа, поэтому я не могу использовать подзапрос. Кроме того, я хочу сохранить поведение, в котором запрос удаляет точно указанное число или записи - например, если таблица содержит 30 строк, но все они имеют одну и ту же метку времени, я все равно хочу удалить 10, хотя это не имеет значения который 10.

Итак, как удалить фиксированное количество строк с сортировкой в ​​PostgreSQL?

Изменить: никакой первичный ключ не означает столбец log_id или аналогичный. Ах, радости унаследованных систем!

Ответ 1

Вы можете попробовать использовать ctid:

DELETE FROM logtable
WHERE ctid IN (
    SELECT ctid
    FROM logtable
    ORDER BY timestamp
    LIMIT 10
)

ctid:

Физическое расположение версии строки в ее таблице. Обратите внимание, что хотя ctid можно использовать для быстрого поиска версии строки, строка ctid изменится, если она будет обновлена ​​или перемещена на VACUUM FULL. Поэтому ctid бесполезен как идентификатор длинной строки.

Там также oid, но это существует только в том случае, если вы специально запрашиваете его при создании таблицы.

Ответ 2

Postgres docs рекомендуют использовать массив вместо IN и подзапроса. Это должно работать намного быстрее

DELETE FROM logtable 
WHERE id = any (array(SELECT id FROM logtable ORDER BY timestamp LIMIT 10));

Этот и некоторые другие трюки можно найти здесь

Ответ 3

delete from logtable where log_id in (
    select log_id from logtable order by timestamp limit 10);

Ответ 4

Предполагая, что вы хотите удалить ЛЮБЫЕ 10 записей (без заказа), вы можете сделать это:

DELETE FROM logtable as t1 WHERE t1.ctid < (select t2.ctid from logtable as t2  where (Select count(*) from logtable t3  where t3.ctid < t2.ctid ) = 10 LIMIT 1);

В моем случае использования, удалив 10M записей, это оказалось быстрее.

Ответ 5

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