Primary key vs foreign key: разница
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Короткий ответ
- Primary key (PK) — уникальный идентификатор строки в таблице. Нельзя NULL, нельзя дубли.
- Foreign key (FK) — ссылка из одной таблицы на PK другой. Обеспечивает связь между таблицами.
PK говорит: «Я — ключ этой таблицы». FK говорит: «Я — указатель на чью-то другую PK».
Пример
CREATE TABLE users (
id INT PRIMARY KEY, -- PK
email VARCHAR(255) UNIQUE,
name VARCHAR(100)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY, -- PK для orders
user_id INT REFERENCES users(id), -- FK на users.id
total DECIMAL(10, 2),
created_at TIMESTAMP
);users.id— primary key таблицы usersorders.order_id— primary key таблицы ordersorders.user_id— foreign key, ссылается наusers.id
Primary key подробнее
Свойства PK
- Уникальность: нет двух строк с одинаковым значением
- NOT NULL: значение обязательно
- Immutable: в хороших практиках не меняется после создания
- Индекс: автоматически создаётся уникальный индекс
Один столбец или несколько (composite key)
-- одна колонка
PRIMARY KEY (id)
-- composite (несколько колонок)
PRIMARY KEY (order_id, product_id)Типичные варианты
- Auto-increment integer:
id SERIAL PRIMARY KEY(Postgres) илиid INT AUTO_INCREMENT PRIMARY KEY(MySQL) - UUID: для распределённых систем
- Natural key:
emailкак PK (риск: email может меняться)
Foreign key подробнее
Свойства FK
- Значение должно существовать в referenced таблице (или быть NULL)
- Может быть NULL (если столбец позволяет)
- Не обязательно уникальный (обычно один user → много orders)
- Автоматически НЕ создаёт индекс (рекомендуется создавать вручную для performance)
Создание
-- inline
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT REFERENCES users(id)
);
-- named constraint
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id)
);
-- добавить к существующей таблице
ALTER TABLE orders
ADD CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users(id);ON DELETE / ON UPDATE
Что делать, когда удаляют / обновляют строку в referenced таблице:
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE -- удалить дочерние
ON UPDATE CASCADE -- обновить дочерние
-- или
ON DELETE SET NULL -- поставить NULL
ON DELETE SET DEFAULT -- поставить DEFAULT
ON DELETE RESTRICT -- запретить удаление (default)
ON DELETE NO ACTION -- то же, что RESTRICTГлавные отличия
| Primary Key | Foreign Key | |
|---|---|---|
| Уникальность | обязательна | не требуется |
| NULL | нельзя | можно |
| Количество в таблице | ровно 1 (составной или нет) | сколько угодно |
| Назначение | уникальный идентификатор | связь между таблицами |
| Индекс | автоматически | нужно создать вручную |
| Referential integrity | сам по себе не обеспечивает | обеспечивает |
Зачем всё это аналитику
Аналитик обычно не создаёт таблицы, но:
- Понимает структуру БД — какая таблица на какую ссылается, как джойнить
- Пишет JOIN — на FK
- Проверяет данные — сироты (orphan records) — строки с FK, которые ссылаются в никуда
- Отличает уникальные сущности от связей — users (PK = id) vs orders (PK = order_id, FK = user_id)
Пример: проверка целостности
Найти orders, которые ссылаются на несуществующих users:
SELECT o.*
FROM orders o
LEFT JOIN users u ON u.id = o.user_id
WHERE u.id IS NULL;Если в БД есть FK — таких строк быть не должно. Если есть — или FK выключен, или баг при insert.
Composite primary key
Используется, когда уникальность обеспечивается сочетанием колонок:
CREATE TABLE order_items (
order_id INT,
product_id INT,
qty INT,
PRIMARY KEY (order_id, product_id), -- composite PK
FOREIGN KEY (order_id) REFERENCES orders(order_id),
FOREIGN KEY (product_id) REFERENCES products(product_id)
);Каждая пара (order_id, product_id) уникальна: один заказ не может содержать один и тот же товар дважды.
Surrogate vs natural key
- Natural key — реальная характеристика (email, СНИЛС)
- Surrogate key — искусственный (auto-increment id)
Обычно предпочитают surrogate: natural могут меняться (человек меняет email).
Частые ошибки
Ошибка 1. FK без индекса
Без индекса на FK-колонку JOIN работает медленно. Создавайте индекс:
CREATE INDEX idx_orders_user_id ON orders(user_id);Ошибка 2. Забывать FK
Без FK в БД оказываются orphan-records. JOIN даёт NULL, статистика врёт.
Ошибка 3. CASCADE DELETE без понимания
Удаление пользователя удаляет его заказы → потеря финансовых данных. Обычно для финансов — ON DELETE RESTRICT или soft-delete.
Ошибка 4. Несколько PK на таблицу
Невозможно технически. Composite PK — это ОДИН PK из нескольких колонок. «Два PK» — неверный термин.
Ошибка 5. NULL в FK — путаница
FK может быть NULL, если столбец допускает. Это означает «нет связи», не «сломанная связь».
Связанные темы
- JOIN SQL — шпаргалка
- Индексы SQL — шпаргалка
- Нормализация БД — шпаргалка
- Как объединить таблицы в SQL
FAQ
Может ли быть таблица без PK?
Технически да (для staging / временных). Но в нормальной БД — всегда PK.
Может ли FK быть NULL?
Да, если столбец NULLable. Означает «связи нет».
Сколько FK может быть в таблице?
Неограниченно (в разумных пределах). Junction tables часто имеют 2-3 FK.
PK всегда integer?
Нет. Может быть UUID, string, composite. Integer auto-increment — популярный выбор, но не единственный.
Тренируйте SQL — откройте тренажёр с 1500+ вопросами для собесов.