Один или два основных ключа во многих таблицах?

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

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

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

  • UserWidgets1: UserWidgetID (PK), WidgetID (FK), UserID (FK)
  • UserWidgets2: WidgetID (PK, FK), UserID (PK, FK)

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

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

Ответы

Ответ 1

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

Перейдите с опцией 2.

Ответ 2

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

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

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

Ответ 3

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

Существуют ситуации, когда вы можете использовать суррогатный ключ (вариант 1)

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

Ответ 6

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

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

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

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

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

Ответ 7

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

Услышьте меня:

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

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

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

Ответ 8

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

Ответ 9

Пользователь userwidgetid в первой таблице не нужен, так как вы сказали, что уникальность исходит из комбинации widgetid и userid.

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

Итак:

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

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