Чем отличается структура базы без внешних ключей от структуры с внешними ключами
Что проверяют
Понимаете ли вы, кто отвечает за целостность данных, когда её не сторожит база. За вопросом обычно стоит рабочая ситуация: сервис на Go пишет в несколько таблиц, часть связей уехала в другую базу или в соседний сервис, и надо решить, где держать проверки.
Как отвечать
Внешний ключ это правило, которое проверяет сама база: нельзя вставить ссылку на несуществующую строку и нельзя удалить строку, на которую ссылаются, если не задано поведение вроде ON DELETE CASCADE или SET NULL. Гарантия работает всегда, кто бы ни пришёл с запросом: приложение, миграция или человек в psql.
Без внешних ключей проверка переезжает в код. Это осознанный выбор в нескольких случаях:
- связь идёт между сервисами с разными базами, и ключу просто некуда встать;
- таблица шардирована или партиционирована, и связь через границу база не проверит;
- массовая загрузка, где проверка каждой строки дорога, а данные валидируются отдельным шагом.
Дальше назовите цену. Код не заменяет ограничение: два параллельных запроса легко создают ссылку на строку, которую соседняя транзакция уже удалила, и без уникального ограничения или явной блокировки эту гонку не закрыть. Отсюда разумная позиция: внутри одной базы ключи ставим, через границу компенсируем явно, идемпотентной обработкой, регулярной сверкой и мягким удалением вместо физического.
Где спотыкаются
Считают, что без ключей всегда быстрее. Сама проверка стоит недорого, а вот отсутствие индекса на дочерней стороне превращает удаление родителя в полный проход по таблице, и именно поэтому база с ключами кажется медленной без настоящей причины.
Второе: не думают про блокировки. Проверка ссылки удерживает родительскую строку, поэтому массовые вставки детей к одному родителю выстраиваются в очередь, а разный порядок обхода таблиц в транзакциях даёт взаимные блокировки.
Третье: полагаются на каскадное удаление как на удобную кнопку. Каскад срабатывает молча и способен снести куда больше, чем ожидал автор запроса, поэтому для данных, которые нужны в отчётности, чаще выбирают запрет удаления или признак неактивности.