Один или два первичных ключа в таблице «многие-ко-многим»?

StackOverflow https://stackoverflow.com/questions/38870

Вопрос

В моей базе данных есть следующие таблицы, которые имеют отношение «многие ко многим», которое выражается соединительной таблицей, имеющей внешние ключи к первичным ключам каждой из основных таблиц:

  • Виджет:ID виджета (PK), название, цена
  • Пользователь:Идентификатор пользователя (ПК), Имя, Фамилия

Предположим, что каждая комбинация «Пользователь-Виджет» уникальна.Я вижу два варианта структурирования соединительной таблицы, определяющей отношения данных:

  1. ПользовательВиджеты1:UserWidgetID (ПК), WidgetID (ФК), UserID (ФК)
  2. ПользовательскиеВиджеты2:ID виджета (ПК, ФК), UserID (ПК, ФК)

Вариант 1 имеет один столбец для первичного ключа.Однако в этом нет необходимости, поскольку единственные данные, хранящиеся в таблице, — это отношения между двумя первичными таблицами, и эти отношения сами по себе могут формировать уникальный ключ.Это приводит к варианту 2, который имеет первичный ключ из двух столбцов, но теряет уникальный идентификатор из одного столбца, который есть у варианта 1.Я также мог бы добавить в первую таблицу уникальный индекс из двух столбцов (WidgetID, UserID).

Есть ли какая-либо реальная разница между ними с точки зрения производительности или какая-либо причина предпочесть один подход другому для структурирования таблицы UserWidgets «многие-ко-многим»?

Это было полезно?

Решение

В любом случае у вас есть только один первичный ключ.Второй — это так называемый составной ключ.Нет веской причины для введения новой колонки.На практике вам придется хранить уникальный индекс для всех потенциальных ключей.Добавление нового столбца не принесет вам ничего, кроме накладных расходов на обслуживание.

Используйте вариант 2.

Другие советы

Лично я бы иметь столбец синтетического/суррогатного ключа в таблицах «многие-ко-многим» по следующим причинам:

  • Если вы использовали числовые синтетические ключи в своих таблицах сущностей, то их использование в таблицах отношений обеспечивает согласованность в дизайне и соглашении об именах.
  • В будущем может случиться так, что сама таблица «многие-ко-многим» станет родительской сущностью для подчиненной сущности, которой потребуется уникальная ссылка на отдельную строку.
  • На самом деле он не будет использовать так много дополнительного дискового пространства.

Синтетический ключ не является заменой естественного/составного ключа и не становится его PRIMARY KEY для этой таблицы только потому, что это первый столбец в таблице, поэтому я частично согласен со статьей Джоша Беркуса.Однако я не согласен с тем, что естественные ключи всегда являются хорошими кандидатами для PRIMARY KEY's и, конечно же, их не следует использовать, если они будут использоваться в качестве внешних ключей в других таблицах.

Вариант 2 использует простой составной ключ, вариант 1 — суррогатный ключ.Вариант 2 предпочтителен в большинстве сценариев и близок к реальной модели, поскольку является хорошим кандидатом на ключ.

В некоторых ситуациях вам может потребоваться использовать суррогатный ключ (вариант 1).

  1. Вы не утверждаете, что составной ключ со временем станет хорошим кандидатом на ключ.Особенно с временными данными (данными, которые меняются со временем).Что, если вы хотите добавить еще одну строку в таблицу UserWidget с теми же UserId и WidgetId?Подумайте о занятости(EmployeeId,EmployeeId) — это сработает в большинстве случаев, за исключением случаев, когда кто-то позже вернется на работу к тому же работодателю.
  2. Если вы создаете сообщения/бизнес-транзакции или что-то подобное, для интеграции которых требуется более простой ключ.Репликация может быть?
  3. Если вы хотите создать свои собственные механизмы аудита (или аналогичные) и не хотите, чтобы ключи были слишком длинными.

Как правило, при моделировании данных вы обнаружите, что большинство ассоциативных объектов (многие ко многим) являются результатом какого-либо события.Человек устраивается на работу, товар добавляется в корзину и т. д.Большинство событий имеют временную зависимость от события, где важна дата или время — и в этом случае лучшей альтернативой может быть суррогатный ключ.

Итак, выберите вариант 2, но убедитесь, что у вас есть полная модель.

Согласен с предыдущими ответами, но хочу добавить одно замечание.Если вы хотите добавить больше информации в отношение и разрешить больше отношений между одними и теми же двумя объектами, вам нужен первый вариант.

Например, если вы хотите отслеживать все случаи, когда пользователь 1 использовал виджет 664, в таблице userwidget идентификатор пользователя и виджет больше не являются уникальными.

В чем преимущество первичного ключа в этом сценарии?Рассмотрим вариант без первичного ключа:ПользовательскиеВиджеты3:ID виджета (ФК), UserID (ФК)

Если вам нужна уникальность, используйте либо составной ключ (UserWidgets2), либо ограничение уникальности.

Обычное преимущество в производительности от наличия первичного ключа заключается в том, что вы часто запрашиваете таблицу по первичному ключу, что происходит быстро.В случае таблиц «многие ко многим» вы обычно не выполняете запрос по первичному ключу, поэтому выигрыша в производительности нет.Таблицы типа «многие-ко-многим» запрашиваются по их внешним ключам, поэтому вам следует рассмотреть возможность добавления индексов по WidgetID и UserID.

Вариант 2 является правильным ответом, если только у вас нет действительно веской причины добавить суррогатный цифровой ключ (что вы и сделали в варианте 1).

Столбцы суррогатного числового ключа не являются «первичными ключами».Первичные ключи технически представляют собой комбинацию столбцов, которые однозначно идентифицируют запись в таблице.

Любой, кто создает базу данных, должен прочитать эту статью. http://it.toolbox.com/blogs/database-soup/primary-keyvil-part-i-7327 Джош Беркус, чтобы понять разницу между столбцами суррогатного числового ключа и первичными ключами.

По моему опыту, единственная реальная причина добавить суррогатный числовой ключ в вашу таблицу — это если ваш первичный ключ является составным ключом и его необходимо использовать в качестве ссылки на внешний ключ в другой таблице.Только тогда вам стоит задуматься о добавлении в таблицу еще одного столбца.

Всякий раз, когда я вижу структуру базы данных, в которой каждая таблица имеет столбец «id», скорее всего, она была разработана кем-то, кто не ценит реляционную модель, и в ней обязательно будет отображаться одна или несколько проблем, выявленных в статье Джоша.

Я бы пошел с обоими.

Выслушай меня:

Составной ключ, очевидно, является хорошим и правильным способом отражения смысла ваших данных.Нет вопросов.

Однако:У меня были всевозможные проблемы с правильной работой спящего режима, если вы не использовали один сгенерированный первичный ключ - суррогатный ключ.

Поэтому я бы использовал логические и физические данные модель.Логический имеет составной ключ.Физическая модель, реализующая логическую модель, имеет суррогатный ключ и внешние ключи.

Поскольку каждая комбинация «Пользователь-Виджет» уникальна, вы должны отразить это в своей таблице, сделав комбинацию уникальной.Другими словами, выберите вариант 2.В противном случае у вас могут быть две записи с одинаковыми идентификаторами виджета и пользователя, но разными идентификаторами пользовательского виджета.

Идентификатор пользователя в первой таблице не требуется, поскольку, как вы сказали, уникальность достигается за счет комбинации идентификатора виджета и идентификатора пользователя.

Я бы использовал вторую таблицу, сохранил внешние ключи и добавил уникальный индекс для виджетов и идентификаторов пользователей.

Так:

userwidgets( widgetid(fk), userid(fk),
             unique_index(widgetid, userid)
)

Отсутствие дополнительного первичного ключа дает некоторый выигрыш в производительности, поскольку базе данных не нужно будет вычислять индекс для ключа.В приведенной выше модели этот индекс (через unique_index) все равно рассчитывается, но я считаю, что это проще понять.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top