Прежде всего: первое (ноль!), Что вы должны сделать, заметив некрасивое время запроса, - убедиться, что у вас недавно было VACUUM ANALYZE
d.
Если вам просто нужно одноразовое удаление, см. ответ araqnid . Но если вам нужно что-то, что продолжит работать в будущем, когда некоторые строки имеют ненулевое, ненулевое поле parent_block_id
, читайте дальше.
Я предполагаю, что PostgreSQL не объединяет удаления, вызванные ON DELETE CASCADE
, в один запрос - тот факт, что вывод EXPLAIN
показывает их как триггеры, предполагает, что удаление каждой дочерней строки фактически будет выполняться отдельно , Предположительно, каждая строка будет найдена с помощью индексированного поиска на parent_block_id
, но это все равно будет намного медленнее, чем один проход по таблице.
Таким образом, вы, вероятно, могли бы добиться большого ускорения, изменив ON DELETE CASCADE
на ON DELETE RESTRICT
и вручную составив список всех удалений, которые необходимо выполнить во временной таблице, а затем удалив их все сразу. Этот подход будет очень быстрым, если максимальная глубина вашей иерархии мала. Вот некоторый псевдокод:
# Insert the top-level rows as "seed" rows.
INSERT INTO rows_to_delete
SELECT id, 0 FROM infoblocks WHERE template_id = 112
# Gather all rows that are children of any row at depth curLevel,
# advancing curLevel until no more children are found.
curLevel = 0
while (nRowsReturnedFromLastInsert > 0) {
INSERT INTO rows_to_delete
SELECT ib.id, rtd.level + 1
FROM infoblocks ib
JOIN rows_to_delete rtd ON (ib.parent_block_id = rtd.id)
WHERE rtd.level = curLevel
curLevel = curLevel + 1
}
DELETE FROM infoblocks
JOIN rows_to_delete rtd ON (infoblocks.id = rtd.id)
(я не уверен, но на самом деле вам может понадобиться использовать ON DELETE NO ACTION
вместо ON DELETE RESTRICT
для того, чтобы окончательный DELETE
был успешным - мне не ясно, допустимо ли одно DELETE
утверждение удалить родителя и всех его потомков, когда действует ON DELETE RESTRICT
. Если по какой-то причине это неприемлемо, вы всегда можете просмотреть несколько операторов DELETE
, сначала удалив самый нижний уровень, затем следующий-самый нижний и т. д.)