Как удалить фиксированное количество строк с сортировкой в ​​PostgreSQL? - PullRequest
86 голосов
/ 02 марта 2011

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

DELETE FROM logtable ORDER BY timestamp LIMIT 10;

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

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

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

Ответы [ 6 ]

128 голосов
/ 02 марта 2011

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

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

ctid:

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

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

41 голосов
/ 02 марта 2011

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

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

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

11 голосов
/ 02 марта 2011
delete from logtable where log_id in (
    select log_id from logtable order by timestamp limit 10);
2 голосов
/ 18 декабря 2013

Предполагая, что вы хотите удалить ЛЮБЫЕ 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);

Для моего случая использования удаление 10М записей оказалось быстрее.

1 голос
/ 02 марта 2011

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

0 голосов
/ 28 июня 2018

Если у вас нет первичного ключа, вы можете использовать синтаксис массива Where IN с составным ключом.

delete from table1 where (schema,id,lac,cid) in (select schema,id,lac,cid from table1 where lac = 0 limit 1000);

Это сработало для меня.

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