Ответ 1
Вот как эти два подхода будут физически представлены в базе данных:
Проанализируем оба подхода...
Подход 1 (оба направления хранятся в таблице):
- PRO: упрощенные запросы.
- CON: данные могут быть повреждены вводом/обновлением/удалением только одного направления.
- MINOR PRO: не требует дополнительных ограничений для обеспечения дублирования дружбы.
- Необходим дальнейший анализ:
- TIE: один индекс охватывает в обоих направлениях, поэтому вам не нужен вторичный индекс.
- TIE: требования к хранению.
- TIE: производительность.
Подход 2 (только одно направление, сохраненное в таблице):
- CON: Более сложные запросы.
- PRO: Невозможно испортить данные, забыв обращаться с противоположным направлением, поскольку нет противоположного направления.
- MINOR CON: Требуется
CHECK(UID < FriendID)
, поэтому одна и та же дружба никогда не может быть представлена двумя разными способами, а ключ на(UID, FriendID)
может выполнять свою работу. - Необходим дальнейший анализ:
- TIE: для cover требуются два индекса: оба направления запроса (составной индекс на
{UID, FriendID}
и составной индекс на{FriendID, UID}
). - TIE: требования к хранению.
- TIE: производительность.
- TIE: для cover требуются два индекса: оба направления запроса (составной индекс на
Особый интерес представляет точка 1. MySQL/InnoDB всегда кластеры, а вторичные индексы могут быть дорогими в кластеризованных таблицах (см. "Недостатки кластеризации" в в этой статье), поэтому может показаться, что вторичный индекс в подходе 2 съел все преимущества меньшего количества строк. Однако, вторичный индекс содержит те же самые поля, что и первичный (только в обратном порядке), поэтому в этом конкретном случае нет накладных расходов на хранение. Также нет указателя на кучу таблицы (так как нет кучи таблиц), поэтому, вероятно, даже более дешевое хранилище, чем обычный индекс на основе кучи. И если запрос покрывается индексом, не будет двойного поиска, обычно связанного со вторичным индексом в кластерной таблице. Таким образом, это в основном связь (ни подход 1, ни подход 2 не имеют значительного преимущества).
точка 2 связана с точкой 1: не имеет значения, будет ли у нас B-дерево значений N или двух B-деревьев, каждое из которых имеет N/2 значения. Так что это также связь: оба подхода будут использовать примерно столько же памяти.
То же рассуждение относится к точке 3: мы ищем одно большее B-Tree или два меньших, не имеет большого значения, так что это тоже связь.
Итак, для надежности и, несмотря на несколько более уродливые запросы и необходимость в дополнительном CHECK
, я бы пошел с подходом 2.