Один или два основных ключа во многих таблицах?
У меня есть следующие таблицы в моей базе данных, которые имеют отношение "многие ко многим", которое выражается таблицей соединений, которая имеет внешние ключи к основным ключам каждой из основных таблиц:
- Виджет: 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) все еще вычисляется, но я считаю, что это легче понять.