Чи слід використовувати кілька первинних ключових стовпців або додати новий стовпець?


15

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

Тож, які недоліки я можу побачити в цьому підході чи причини, за якими я можу отримати один ключ стовпця?


2
Я не знаю, я думаю, що це було б краще на SO.
FrustratedWithFormsDesigner

2
@FrustratedWithFormsDesigner Це може перейти до SO, але я думаю, що він працює і тут, оскільки фокус питання, як видається, приділяється саме тому, "які плюси та мінуси цього підходу", а не "як мені зробити X?".
Адам Лір

@Anna Lear ♦: Це "за і проти" дизайнерських рішень, які матимуть прямий і певний вплив на кодування, тому я думаю, що ТАК буде кращим місцем.
FrustratedWithFormsDesigner

Відповіді:


8

Зазвичай, коли у вас є таблиця з багатоколонним первинним ключем, це результат таблиці приєднання (багато-багато-багато), яка стала підвищеною, щоб бути її власною сутністю (і, таким чином, заслуговує на те, що це власний первинний ключ). Є багато людей, які б заперечували, що будь-яка таблиця приєднання БУДЬ за замовчуванням сутність, але це обговорення для іншого дня.

Давайте розглянемо гіпотетичні відносини «багато до багатьох»:

Учень * --- * Клас

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

Між цими двома таблицями буде розміщена таблиця переходу під назвою StudentClass (або ClassStudent залежно від того, як ви її записуєте). Іноді хочеться відслідковувати такі речі, як колись учень був у класі. Тож ви додасте його до таблиці StudentClass. На даний момент StudentClass став унікальною сутністю ... і йому слід дати ім'я, щоб визнати його таким, наприклад, Зарахування.

Учень 1 --- * Зарахування * --- 1 клас

(Учень може мати багато Реєстрацій; кожен Запис призначений для одного класу (або йде навпаки, якщо Клас може мати багато Реєстрацій, кожен Запис призначений для одного Студента).

Тепер ви можете запитати такі речі, скільки учнів було зараховано до класу Хімія 101 минулого року? Або в які класи навчався студент Джон До, відвідуючи університет Acme? Це було можливо без окремого первинного ключа, але як тільки у вас є первинний ключ для зарахування, легшим буде запит із цих записів (за ідентифікатором), скільки учнів отримали прохідну оцінку?

Визначення того, чи заслуговує суб'єкт господарювання ПК, зводиться до того, скільки запитів (або маніпуляцій) ви зробите для цієї сутності. Скажімо, наприклад, ви хотіли прикріпити завдання, виконані для учня, в класі. Логічним місцем для приєднання цього об'єкта (Присвоєння) було б суб'єкт реєстрації. Якщо записати свій власний первинний ключ, це спростить запити про призначення.


1
Тож ви додасте його до таблиці StudentClass. На даний момент StudentClass став унікальною сутністю ... і йому слід дати ім'я, щоб визнати його таким, наприклад, Зарахування. Це така проста річ, але в цьому є велика цінність!
Ботіс

8

Має сенс мати окремий стовпчик ідентифікатора. Коли ви хочете отримати щось із таблиці бази даних, це зробити простіше:

SELECT whatever FROM table WHERE id=13

ніж ВИБІРТЕ, що з таблиці, де col1 = 'val1' AND col2 = 'val2' AND 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запитів. І, Б) , я не маю уявлення, як це насправді викликає будь-який тип вимоги до URL-адреси (якщо ви не працюєте з поганою рамкою). Мої URL-адреси не містять жодних рядків запитів ?id=13, не кажучи вже про них ?col1=val1&col2=val2&col3=val3.
Ніколь

2
@renesis: на цьому веб-сайті є унікальні запитання та користувачі, які вказані в URL-адресах. Хоча це дещо особливий випадок, оскільки ці конкретні дані не змінюються.
Майкл К

1
@ Renesis, більшість (можливо, всі) сучасних db мають цілочисельні типи стовпців auto_increment, які можуть генерувати ідентифікатори автоматично і безпечно, і повідомляти про них за допомогою запиту sql або виклику функції бібліотеки. Або в розподіленому середовищі ви використовуєте великий випадковий хеш. Деякі БД навіть зроблять прихований стовпчик ідентифікатора для вас, якщо у вас його немає в таблиці.
GrandmasterB

@Michael - Я не сказав, що ідентифікатори ніколи не містять URL-адрес. Звичайно, вони є. Якщо у вас є URL-адреси, які представляють рядок даних, то так, ці дані, мабуть, мають унікальний ідентифікатор. Якщо якась інша частина URL-адреси вже не містить інших частин клавіші. @GrandmasterB Жодна з двох останніх компаній, над якими я працював (понад 6 років), і обидві, які використовують MySQL (одна також підтримує Oracle і SQL Server), не змогли використовувати автоматичне збільшення, ані великий випадковий хеш.
Ніколь

8

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

Я вважаю за краще сурогатні ключі, оскільки вони спрощують адміністрування протягом життя БД (вам ніколи не потрібно турбуватися про те, що значення ключів змінюють значення, що ніколи не повинно відбуватися, але це відбувається в будь-якій реальній системі, де задіяні люди). Однак якщо в БД є багато таблиць "пошуку" (тобто таблиць, які в основному є ключовими: парами значень), сурогатні ключі можуть стати громіздкими, оскільки вам потрібно приєднати ці таблиці до запиту, щоб отримати значущі результати.

Наприклад, скажімо, що у вас є два об'єкти: Адреса та Країна.

  • Відносини такі: Адреса * ----- 1 Країна
  • Суб'єкт країни в основному є ключовим: пара значень (наприклад, США: США, Каліфорнія: Канада, MX: Мексика тощо)
  • Для запиту цієї структури для всіх адрес у США:

select * from Address where CountryCode = 'US'

  • Щоб виконати той самий запит із сурогатними ключами:

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

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


5

Це залежить від того, як ви отримуєте доступ до даних. Якщо ви робите велику кількість часткових ключів (де ви вибираєте записи на основі, скажімо, лише двох з трьох клавіш), тоді ви хочете зберегти багаточастинні клавіші. ОТОХ, якщо у вас багато стосунків 1: 1 з іншими таблицями, можливо, має більше сенсу мати сурогатний ключ.


1

Мені подобається завжди мати сурогатний первинний ключ для кожної таблиці. Але не так багато «важких» причин для того, щоб переконатись у тому, що я чув.

Один раз, коли я коли-небудь переживав багатоколонний природний ключ, мене було з ORM. Інколи у мене виникають проблеми з первинним ключем з декількома стовпцями за допомогою Linq To Entities.


1

Ніколи не кажіть ніколи, але приєднання до 4 колонок - це біль. Чим більше у вас стовпців з інтелектуальними даними, тим більше шансів зміни цих значень. Бази даних можуть бути налаштовані на підтримку референтної цілісності з каскадними оновленнями.

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

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


0

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

Я не знаходжу цього в допомозі (особливо зі зберіганням даних), коли маємо справу з таблицями фактів / деталей. Канонічний приклад таблиці фактів продажу з (кількість клієнтів, магазин_ ключ, продукт_кейк) з кількістю не має особливого сенсу мати ключ рівня запису.


0

Наявність PK для автоматичного збільшення int зменшує клопоту, якщо ви виявите, що ваш складовий ключ насправді може мати дублікати.


0

Існує хороша дискусія, що починається з 2002 року про Ask Tom . Це специфічно для Oracle, але більш широке обговорення стосується будь-якої бази даних, яку ви використовуєте.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.