Должен ли я использовать несколько первичных ключей столбцов или добавить новый столбец?

15

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

Итак, какие недостатки я могу видеть в этом подходе или причины, по которым мне может потребоваться один столбец?

COVAR
источник
2
Я не знаю, я думаю, что это было бы лучше на SO.
FrustratedWithFormsDesigner
2
@FrustratedWithFormsDesigner Это может пойти на SO, но я думаю, что это также работает и здесь, так как вопрос, как представляется, сосредоточен на том, «каковы плюсы и минусы этого подхода», а не «как мне сделать X?».
Адам Лир
@ Анна Лир ♦: Это "плюсы и минусы" в проектных решениях, которые будут иметь прямое и определенное влияние на кодирование, поэтому я думаю, что SO будет лучшим местом.
FrustratedWithFormsDesigner

Ответы:

8

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

Давайте посмотрим на гипотетические отношения многих ко многим:

Студент * --- * Класс

(Студент может быть в нескольких классах, класс может иметь несколько студентов).

Между этими двумя таблицами будет таблица соединений с именем StudentClass (или ClassStudent в зависимости от того, как вы ее напишите). Иногда вы хотите отслеживать такие вещи, как когда ученик был в классе. Таким образом, вы добавите его в таблицу StudentClass. На этом этапе StudentClass стал уникальным объектом ... и ему должно быть присвоено имя для распознавания, например, Enrollment.

Студент 1 --- * Зачисление * --- 1 класс

(у студента может быть много Зачислений, каждая Зачисление предназначена для одного класса (или наоборот, класс может иметь много Записей, каждая Зачисление предназначена для одного Студента).

Теперь вы можете задавать вопросы о том, сколько студентов было зачислено в класс химии 101 в прошлом году? Или в какие классы был зачислен студент Джон Доу, когда учился в университете Акме? Это было возможно без отдельного первичного ключа, но если у вас есть первичный ключ для зачисления, то будет проще запросить эти зачисления (по идентификатору), сколько учеников получили проходной балл?

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

Майкл Браун
источник
1
Таким образом, вы добавите его в таблицу StudentClass. На этом этапе StudentClass стал уникальным объектом ... и ему должно быть присвоено имя для распознавания, например, Enrollment. Это такая простая вещь, но в этом так много ценности!
Botis
8

Имеет смысл иметь отдельный столбец id. Когда вы хотите получить что-то из таблицы базы данных, это проще сделать:

SELECT whatever FROM table WHERE id=13

чем выбрать любую из таблицы, где col1 = 'val1' и col2 = 'val2' и col3 = 'val3'

Например, в веб-приложении это выглядит как URL:

www.somewebsite.com/somepage.php?id=13

или вот так:

www.somewebsite.com/somepage.php?col1=val1&col2=val2&col3=val3
инфракрасный
источник
4
И гораздо проще добавить связанную таблицу, когда вы можете связать Id вместо нескольких столбцов
CaffGeek
3
Извините, на данный момент я должен -1, как а) это не черный и белый. Добавление столбца идентификаторов сопровождается негативами, например, где и когда вы генерируете этот новый идентификатор. Кроме того, это может привести к дополнительным соединениям или SELECTзапросам. И, B) , я не имею ни малейшего представления, как это на самом деле вызывает какие-либо требования к URL (если вы не работаете с плохой платформой). Мои URL не содержат строк запроса ?id=13, не говоря уже о ?col1=val1&col2=val2&col3=val3.
Николь
2
@renesis: на этом сайте есть уникальные вопросы и пользователи, которые есть в URL. Хотя это в некотором роде особый случай, поскольку эти конкретные данные не меняются.
Майкл К
1
@Renesis, большинство (возможно, все) современных БД имеют целочисленные типы столбцов auto_increment, которые могут автоматически и безопасно генерировать идентификаторы и сообщать о них через SQL-запрос или вызов функции библиотеки. Или в распределенной среде вы используете большой случайный хеш. Некоторые БД даже сделают для вас скрытый столбец идентификатора, если у вас его еще нет в таблице.
GrandmasterB
@ Майкл - я не говорил, что идентификаторы никогда не встречаются в URL. Конечно они есть. Если у вас есть URL-адреса, представляющие строку данных, то да, эти данные, вероятно, должны иметь уникальный идентификатор. Если какая-то другая часть URL-адреса уже содержит другие части мультиключа. @GrandmasterB Ни одна из двух последних компаний, в которых я работал (более 6 лет), обе из которых используют MySQL (одна также поддерживала Oracle и SQL Server), не могла использовать автоинкремент или большой случайный хэш.
Николь
8

В основном вы спрашиваете, должны ли вы использовать суррогатные или натуральные ключи (в вашем случае это звучит как составные натуральные ключи). Вот отличная статья: http://www.agiledata.org/essays/keys.html

Я предпочитаю суррогатные ключи, потому что они упрощают администрирование в течение всей жизни БД (вам никогда не придется беспокоиться о последствиях изменения значения ключей, что никогда не должно происходить, но происходит в любой реальной системе, где задействованы люди). Однако , если в БД много таблиц «поиска» (т. Е. Таблиц, которые в основном являются парами ключ: значение), то суррогатные ключи могут стать громоздкими, потому что вам нужно объединить эти таблицы в запрос, чтобы получить значимые результаты.

Например, допустим, у вас есть две сущности: адрес и страна.

  • Отношения: Адрес * ----- 1 Страна
  • Сущность Country в основном представляет собой пару ключ: значение (например, США: США, CA: Канада, MX: Мексика и т. Д.)
  • Чтобы запросить эту структуру для всех адресов в США:

select * from Address where CountryCode = 'US'

  • Чтобы выполнить тот же запрос с суррогатными ключами:

select Address.* from Address join Country on Address.CountryID = Country.ID where Country.Code = 'US'

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

Кертис Батт
источник
5

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

TMN
источник
1

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

Один раз, когда у меня когда-либо был укус естественного ключа с несколькими столбцами, был с ORM. Иногда у меня возникают проблемы с первичным ключом из нескольких столбцов, использующим Linq To Entities.

Майк М.
источник
1

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

Вы всегда можете создать другой индекс для обработки уникальных значений.

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

JeffO
источник
0

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

Я не нахожу это помощи (особенно с хранилищем) при работе с таблицами фактов / подробностей. Канонический пример таблицы фактов продаж с (customer_key, store_key, product_key) с количеством не имеет большого смысла иметь ключ уровня записи.

Jé Queue
источник
0

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

Пол Натан
источник
0

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

Рис Гибсон
источник