foundation
Foreign keys
Используйте referential integrity для защиты relationships, понимая cascade behavior и migration constraints.
Foreign key объявляет, что значения дочернего столбца должны существовать в родительской строке (или быть null, если разрешено). БД обеспечивает referential integrity при insert, update и delete — связь не только договорённость в приложении.
CREATE TABLE order_items (
id BIGINT PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE RESTRICT,
product_id BIGINT NOT NULL REFERENCES products(id)
);
| `ON DELETE` / `ON UPDATE` | Эффект | |-----------------------------|--------| | `RESTRICT` / `NO ACTION` | Блокирует изменение родителя при наличии детей | | `CASCADE` | Распространяет delete/update на дочерние строки | | `SET NULL` | Обнуляет FK при удалении родителя |
`CASCADE` упрощает очистку, но может неожиданно снести глубокое дерево и долго держать locks. `RESTRICT` выявляет риск «осиротевших» строк в момент delete. Массовые загрузки и blue/green-миграции иногда временно снимают FK — зафиксируйте окно и перепроверьте целостность после.
На интервью: объясните, зачем FK в схеме для денег и складского учёта, и когда команды откладывают их (шардированные записи, legacy ETL) с компенсирующими проверками.
Типовые ошибки: нет индекса на FK-столбцах (медленные join и проверки locks); цепочки `CASCADE`, удаляющие больше задуманного; целостность только в приложении, проигрывающая гонкам; добавление FK к «грязной» таблице без backfill-аудита.
Компромисс — между корректностью, навязанной БД, и гибкостью миграций / cross-shard ссылок: используйте FK там, где битая связь — инцидент в production, а не повод для логирования.
Чеклист:
- Назовите родительскую и дочернюю таблицы и кардинальность.
- Явно выберите поведение `ON DELETE`.
- Индексируйте каждый FK-столбец в join.
- Опишите migration/backfill до включения constraint.
- Сформулируйте, что ломается при целостности только в приложении.