Что такое ON DELETE CASCADE в PostgreSQL?

MiddlePostgreSQL · Backend·Обновлено 26 августа 2026
Коротко
ON DELETE CASCADE — это опция внешнего ключа, при которой удаление строки в родительской таблице автоматически удаляет все связанные с ней строки в дочерней таблице в рамках той же транзакции.

Суть механизма

ON DELETE CASCADE — это часть определения ограничения FOREIGN KEY, которая указывает, что должно происходить со строками дочерней таблицы при удалении связанной строки родительской таблицы. Если задан CASCADE, PostgreSQL сам удалит все зависимые записи — не нужно вручную писать DELETE FROM child WHERE parent_id = ... перед удалением родителя.

Синтаксис

CREATE TABLE authors (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

CREATE TABLE books (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    author_id INTEGER REFERENCES authors(id) ON DELETE CASCADE
);

Если ограничение уже существует, его нужно пересоздать через ALTER TABLE, так как изменить действие ON DELETE на месте нельзя:

ALTER TABLE books DROP CONSTRAINT books_author_id_fkey;
ALTER TABLE books
    ADD CONSTRAINT books_author_id_fkey
    FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE;

Другие варианты ON DELETE

  • NO ACTION (по умолчанию) — запрещает удаление, если есть ссылающиеся строки (проверка откладывается до конца оператора)
  • RESTRICT — то же самое, но проверка немедленная, без возможности отложить
  • SET NULL — у дочерних строк FK-колонка обнуляется
  • SET DEFAULT — FK-колонке присваивается значение по умолчанию
  • CASCADE — дочерние строки удаляются вместе с родителем

Как это работает изнутри

Каскадное удаление выполняется внутри той же транзакции, что и исходный DELETE. Технически это реализовано через внутренние триггеры, привязанные к ограничению внешнего ключа, а не через явные пользовательские триггеры. Если на любом шаге каскада возникает ошибка (например, срабатывает другое ограничение), вся транзакция атомарно откатывается — частично удалённых данных не остаётся.

Многоуровневый каскад

CASCADE применяется рекурсивно. Если таблица C ссылается на B с ON DELETE CASCADE, а B ссылается на A тоже с ON DELETE CASCADE, то удаление строки в A каскадно удалит связанные строки B, а вслед за ними — связанные строки C.

Риски и практика применения

CASCADE — операция, которая молча и необратимо удаляет данные, поэтому её стоит использовать осознанно:

  • Для действительно строго зависимых сущностей (строки заказа без заказа не имеют смысла) CASCADE уместен
  • Для важных данных, где случайное удаление дорого, чаще выбирают RESTRICT/NO ACTION и явное подтверждение на уровне приложения, либо soft delete (флаг deleted_at) вместо физического удаления
  • Когда связь необязательна, логичнее SET NULL

Производительность

PostgreSQL не создаёт индекс на колонке внешнего ключа автоматически (в отличие от первичного ключа). Без индекса каскадное удаление вызывает полное сканирование дочерней таблицы при каждом удалении родителя, что на больших объёмах данных приводит к деградации и долгим блокировкам. Поэтому на FK-колонку почти всегда стоит добавлять индекс:

CREATE INDEX idx_books_author_id ON books(author_id);

Что хочет услышать интервьюер

Понимание, что CASCADE — это опция FOREIGN KEY, а не отдельная команда или триггер

Знание альтернатив: RESTRICT, NO ACTION, SET NULL, SET DEFAULT и разницу между ними

Понимание атомарности — каскад выполняется в той же транзакции

Осознание рисков: каскад может неожиданно удалить много связанных данных

Знание про отсутствие автоиндекса на FK-колонке и связанные проблемы производительности

Пример: Создание таблиц с ON DELETE CASCADE

CREATE TABLE authors (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL
);

CREATE TABLE books (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    author_id INTEGER REFERENCES authors(id) ON DELETE CASCADE
);

-- при удалении автора все его книги удалятся автоматически
DELETE FROM authors WHERE id = 1;

Пример: Пересоздание ограничения через ALTER TABLE

ALTER TABLE books DROP CONSTRAINT books_author_id_fkey;

ALTER TABLE books
    ADD CONSTRAINT books_author_id_fkey
    FOREIGN KEY (author_id) REFERENCES authors(id) ON DELETE CASCADE;

-- индекс на FK-колонке ускоряет каскадные удаления
CREATE INDEX idx_books_author_id ON books(author_id);

Типичные ошибки

Путают ON DELETE CASCADE с обычным триггером или считают, что нужно писать его вручную

Не знают разницы между RESTRICT и NO ACTION (полагают, что это одно и то же)

Забывают, что многоуровневые связи каскадируются рекурсивно, и недооценивают масштаб удаления

Не упоминают, что PostgreSQL не индексирует FK-колонки автоматически, что делает каскадные удаления медленными

Считают CASCADE безопасным выбором по умолчанию, не обсуждая alternative вроде soft delete

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее