Чем составные ключи отличаются от простых ключей в базах данных
Что проверяют
Понимаете ли вы, что ключ это в первую очередь ограничение уникальности и структура индекса, а не поле id, добавленное по привычке. Плюс умеете ли выбрать между естественным составным ключом и суррогатным.
Как отвечать
Простой ключ это один столбец, составной это упорядоченный набор столбцов, уникальный в совокупности. Слово «упорядоченный» здесь ключевое: индекс по паре столбцов годится для условия по первому и для условия по обоим, но не для условия только по второму. Это правило левого префикса, и его как раз ждут услышать.
Где составной уместен. Таблицы связей, где сущностью является сама пара, например пользователь и роль. Временные ряды, где ключ это объект вместе с моментом времени. Данные из внешней системы, у которых уже есть естественный ключ, и его надо защитить от дублей.
Где лучше суррогат. Когда на таблицу ссылаются другие: составной ключ тянется во все дочерние таблицы целиком. Когда значения ключа со временем меняются. Когда важен размер вторичных индексов: в движках с кластерным первичным ключом каждый вторичный индекс хранит копию первичного, и широкий ключ раздувает их все.
Рабочий компромисс, который стоит назвать: суррогатный идентификатор как первичный ключ плюс отдельное уникальное ограничение на естественный набор полей. В Go это видно и на уровне кода: составной ключ ломает привычную сигнатуру вида получить по идентификатору, и методы репозитория приходится писать под конкретную пару.
Где спотыкаются
Считают составной ключ медленным, потому что столбцов больше. Это один индекс, а не несколько, и на запросах по префиксу он часто быстрее простого, потому что покрывает запрос целиком и позволяет не ходить в таблицу.
Второе: порядок столбцов выбирают наугад. Первым должен идти тот, по которому в запросах всегда есть условие равенства. На маленькой тестовой базе ошибка не видна вообще, она проявляется только в плане запроса на реальных объёмах.
Третье: путают первичный ключ с уникальным ограничением и вешают уникальность на естественные поля вроде имени и фамилии. После этого система не может принять двух тёзок, а починить это можно только миграцией.