Какая связь между таблицами людей и адресов в базе данных
Что проверяют
Умеете ли вы моделировать связь от требований, а не отвечать шаблоном «один ко многим». Интервьюер ждёт уточняющих вопросов о предметной области, а следом обычно спрашивает, как вы достанете людей с адресами из Go без N+1 запросов.
Как отвечать
Начните с вопроса, что значит адрес в этой системе. От ответа зависит схема:
- один ко многим: у человека несколько адресов (домашний, доставки), адрес принадлежит одному человеку. Внешний ключ
person_idлежит вaddresses; - многие к одному: в одной квартире живут несколько человек, адрес это самостоятельная сущность. Тогда
address_idлежит вpeople; - многие ко многим: связующая таблица
person_addresses (person_id, address_id, kind, valid_from)с составным первичным ключом, в ней же удобно хранить тип адреса и период действия; - один к одному: поля проще держать в самой
peopleили в отдельной таблице сUNIQUE (person_id).
Детали, которые отличают опытного разработчика:
- индекс на внешний ключ: PostgreSQL сам его не создаёт, только на первичный ключ и
UNIQUE. Без индекса медленными становятся иJOIN, и удаление человека: база ищет ссылающиеся строки полным сканированием; ON DELETE:CASCADEдля адресов, которые без человека не имеют смысла,RESTRICTдля общих;- история: адрес в заказе обычно копируют, а не ссылаются на него, иначе смена адреса перепишет старые заказы.
В Go не грузите адреса отдельным запросом на каждого человека. Либо один LEFT JOIN и сборка результата в map[int64]*Person, либо второй запрос WHERE person_id = ANY($1) со срезом идентификаторов, который pgx передаёт массивом. Колонки из LEFT JOIN могут быть NULL, поэтому сканируйте их в указатели или sql.NullString. В sqlc структуры генерируются из SQL, в GORM похожую задачу решает Preload.
Где спотыкаются
Сразу рисуют «один ко многим» и не спрашивают про общие адреса, историю и тип адреса.
Забывают индекс на person_id и удивляются медленным выборкам на больших таблицах.
Пишут цикл с запросом на каждую итерацию. На сотне людей это сто походов в базу вместо одного или двух.