Помогают ли внешние ключи (foreign keys) удалять данные в связанных таблицах?

«Помогают ли внешние ключи (foreign keys) удалять данные в связанных таблицах?» — вопрос из категории Базы данных, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Внешние ключи (FK) сами по себе не удаляют данные. Их основная задача — обеспечить целостность ссылочных данных (referential integrity). Они гарантируют, что в дочерней таблице (order_items) не может существовать запись, ссылающаяся на несуществующую запись в родительской таблице (orders).

Однако, при определении внешнего ключа можно задать правило каскадного действия (ON DELETE). Вот как это работает:

-- Родительская таблица
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    customer_id INT NOT NULL,
    total DECIMAL(10,2)
);

-- Дочерняя таблица с внешним ключом и разными правилами ON DELETE
CREATE TABLE order_items (
    id INT PRIMARY KEY AUTO_INCREMENT,
    order_id INT NOT NULL,
    product_id INT NOT NULL,
    quantity INT,
    -- 1. CASCADE: автоматическое удаление дочерних записей
    CONSTRAINT fk_items_order_cascade 
        FOREIGN KEY (order_id) REFERENCES orders(id) 
        ON DELETE CASCADE,

    -- 2. SET NULL: установка NULL в поле внешнего ключа (поле должно быть NULLABLE)
    -- CONSTRAINT fk_items_order_setnull 
    --    FOREIGN KEY (order_id) REFERENCES orders(id) 
    --    ON DELETE SET NULL,

    -- 3. RESTRICT (или NO ACTION): запрет удаления родительской записи, если есть дочерние
    -- CONSTRAINT fk_items_order_restrict 
    --    FOREIGN KEY (order_id) REFERENCES orders(id) 
    --    ON DELETE RESTRICT
);

Практический пример с CASCADE:

-- Вставка данных
INSERT INTO orders (id, customer_id, total) VALUES (101, 1, 150.00);
INSERT INTO order_items (order_id, product_id, quantity) VALUES (101, 500, 2);
INSERT INTO order_items (order_id, product_id, quantity) VALUES (101, 501, 1);

-- Удаление заказа. Благодаря ON DELETE CASCADE, две связанные строки в order_items будут удалены автоматически.
DELETE FROM orders WHERE id = 101;
-- После этого запрос SELECT * FROM order_items WHERE order_id = 101 вернет пустой результат.

Ключевые моменты:

  • ON DELETE CASCADE — это именно то правило, которое «помогает удалять» связанные данные автоматически. Используйте его с осторожностью, так как это может привести к неожиданной потере данных.
  • ON DELETE RESTRICT (или NO ACTION) — это поведение по умолчанию во многих СУБД. Оно не помогает удалить, а наоборот, предотвращает удаление, если существуют зависимые записи, защищая от «висячих» ссылок.
  • ON DELETE SET NULL — не удаляет дочернюю запись, а обнуляет ссылку. Для этого столбец order_id должен быть объявлен как INT NULL.

Вывод: Внешние ключи — это механизм поддержания целостности. Правило ON DELETE CASCADE — это опция, которая автоматизирует удаление зависимых записей, но ее применение должно быть осознанным и соответствовать бизнес-логике (например, удаление заказа должно удалять его позиции, но удаление клиента, вероятно, не должно удалять все его исторические заказы).