Один или два основных ключа в таблице «многие ко многим»? - PullRequest
14 голосов
/ 02 сентября 2008

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

  • Виджет: WidgetID (PK), Название, Цена
  • Пользователь: UserID (PK), FirstName, LastName

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

  1. UserWidgets1: UserWidgetID (PK), WidgetID (FK), UserID (FK)
  2. UserWidgets2: WidgetID (PK, FK), UserID (PK, FK)

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

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

Ответы [ 9 ]

24 голосов
/ 02 сентября 2008

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

Перейти с вариантом 2.

5 голосов
/ 02 сентября 2008

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

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

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

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

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

5 голосов
/ 02 сентября 2008

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

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

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

3 голосов
/ 02 сентября 2008

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

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

2 голосов
/ 02 сентября 2008

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

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

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

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

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

2 голосов
/ 02 сентября 2008

В чем преимущество первичного ключа в этом сценарии? Рассмотрим вариант без первичного ключа: UserWidgets3: WidgetID (FK), UserID (FK)

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

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

1 голос
/ 22 марта 2009

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

Услышь меня:

Составной ключ - это, очевидно, хороший и правильный путь, позволяющий отразить смысл ваших данных. Без вопросов.

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

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

0 голосов
/ 02 сентября 2008

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

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

Итак:

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

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

0 голосов
/ 02 сентября 2008

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

...