← Назад к вопросам

Для чего используется Foreign Key в БД?

1.3 Junior🔥 281 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для чего используется Foreign Key в БД

Foreign Key (внешний ключ) — это механизм реляционной БД, который обеспечивает целостность данных через связи между таблицами. Это один из столпов relational databases.

Основная функция

Foreign Key создаёт связь между двумя таблицами:

  • Главная таблица (parent table) — содержит PRIMARY KEY
  • Зависимая таблица (child table) — содержит FOREIGN KEY, ссылающийся на PRIMARY KEY главной таблицы
-- Главная таблица
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  email VARCHAR(100) UNIQUE NOT NULL
);

-- Зависимая таблица с FOREIGN KEY
CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  title VARCHAR(200),
  content TEXT,
  user_id INTEGER NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id)
);

Основные функции Foreign Key

1. Обеспечение referential integrity (целостности ссылок)

БД гарантирует, что в таблице posts не может быть user_id, который не существует в users.

-- Это сработает
INSERT INTO posts (title, user_id) VALUES ('My Post', 1);
-- где user_id = 1 существует в users

-- Это НЕ сработает — ошибка
INSERT INTO posts (title, user_id) VALUES ('Bad Post', 999);
-- user_id = 999 не существует в users — FOREIGN KEY constraint violation

2. Предотвращение orphaned records (сиротских записей)

Без Foreign Key можно удалить пользователя, оставив посты без владельца:

-- Без FK
DELETE FROM users WHERE id = 1;  -- Посты этого пользователя остаются
-- Теперь есть posts с несуществующим user_id

-- С FK и ON DELETE CASCADE
DELETE FROM users WHERE id = 1;  -- Автоматически удаляет все posts этого пользователя

Типы действий при удалении/обновлении

CASCADE — удаляй зависимые записи

CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  title VARCHAR(200),
  user_id INTEGER NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- DELETE FROM users WHERE id = 1;
-- Автоматически удалит ВСЕ posts где user_id = 1

SET NULL — обнули ссылку

CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  title VARCHAR(200),
  user_id INTEGER,  -- Может быть NULL
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);

-- DELETE FROM users WHERE id = 1;
-- Posts' user_id установится в NULL

RESTRICT — запрети удаление

CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  user_id INTEGER NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
);

-- DELETE FROM users WHERE id = 1;  -- ОШИБКА
-- Cannot delete user while posts exist

NO ACTION (default) — проверь constraint

FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION
-- Не удалит, если есть зависимые посты

Практический пример: соцсеть

-- Пользователи
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) UNIQUE NOT NULL
);

-- Посты пользователей
CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  user_id INTEGER NOT NULL,
  content TEXT,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- Комментарии к постам
CREATE TABLE comments (
  id SERIAL PRIMARY KEY,
  post_id INTEGER NOT NULL,
  user_id INTEGER NOT NULL,
  content TEXT,
  FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- Лайки
CREATE TABLE likes (
  id SERIAL PRIMARY KEY,
  post_id INTEGER NOT NULL,
  user_id INTEGER NOT NULL,
  FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
  UNIQUE(post_id, user_id)  -- Один лайк на пост от пользователя
);

Теперь если удалить пользователя — автоматически удалятся все его посты, комментарии и лайки благодаря CASCADE.

Преимущества Foreign Key

1. Целостность данных на уровне БД

-- Компилятор БД гарантирует:
-- - Нельзя создать пост без существующего пользователя
-- - Нельзя удалить пользователя, если есть посты (при RESTRICT)
-- - Нельзя обновить id пользователя, если на него ссылаются посты

2. Консистентность при множественных операциях

Even if application crashes, БД останется консистентной.

3. Документирование структуры

FK явно показывают связи между таблицами.

4. Оптимизация запросов

QueryPlanner может использовать FK информацию для оптимизации.

Недостатки Foreign Key

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

-- Каждый INSERT/UPDATE/DELETE проверяет FK
INSERT INTO posts (user_id) VALUES (1);  -- БД проверяет: существует ли user_id = 1
-- На больших таблицах это может быть медленным

2. Усложнение удаления и обновления

-- Хочу обновить user.id = 1 на id = 100
-- Но есть миллион постов с user_id = 1
-- БД должна обновить все посты (если ON UPDATE CASCADE)
UPDATE users SET id = 100 WHERE id = 1;

3. Сложность в микросервисной архитектуре

Если users и posts в разных БД — FK не работает.

Best Practices

1. Используй FK для моделирования отношений:

FOREIGN KEY (user_id) REFERENCES users(id)

2. Выбирай правильное ON DELETE действие:

-- CASCADE для dependent records (посты удаляются со своим юзером)
ON DELETE CASCADE

-- SET NULL для optional references (может быть удалён, ссылка обнуляется)
ON DELETE SET NULL

-- RESTRICT для important references (нельзя удалить, пока есть ссылки)
ON DELETE RESTRICT

3. Индексируй Foreign Key:

CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  user_id INTEGER NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id),
  INDEX idx_user_id (user_id)  -- Для быстрого поиска по user_id
);

4. В коде (Node.js/ORM) соблюдай правила FK:

const post = new Post();
post.userId = 999;  // Будет ошибка при save() — FK violation
await post.save();  // TypeError: FOREIGN KEY constraint failed

Вывод: Foreign Key — это критически важный механизм для обеспечения целостности данных в реляционных БД. Используй их для моделирования связей между таблицами, но помни про производительность на больших датасетах. В микросервисной архитектуре FK заменяются на application-level валидацию или event-driven подходы.

Для чего используется Foreign Key в БД? | PrepBro