Як вам первинні ключі? [зачинено]


88

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

  1. Int / BigInt, які автоінкременти є досить хорошими первинними ключами.
  2. Має бути принаймні 3 стовпці, що складають первинний ключ.
  3. Ідентифікатори ідентифікатора GUID та читаного людиною рядка повинні по-різному оброблятися.

Який найкращий підхід для ПК? Було б чудово, якби ви могли б обґрунтувати свою думку. Чи є кращий підхід, ніж вищезазначений?

EDIT: У когось є простий зразок / алгоритм для створення зручних для читання ідентифікаторів рядків, які добре масштабуються?


1
Оскільки це суб'єктивно, це має бути вікі спільноти
Джон Шиган

2
"Має бути принаймні 3 стовпці, що складають первинний ключ"? Що це означає? Чи можете ви надати подальше визначення? Або це частина №3?
S.Lott

@ S.Lott PK(NEWID(),NEWID(),NEWID());-)

@pst: Чому це вимога? Чому в ПК має бути три стовпці? Чому один чи чотири?
S.Lott

Я міг бачити три стовпця PK, схожий на ... LocalID (автоматичне збільшення int), GlobalID (GUID), ForeignId (зовнішній ключ, як RolesType) тощо. LocalID + ForiegnId може бути складеною комбінацією ключів. Посібник використовується для інших веб-сайтів / послуг. Особисто я б цього не робив, я б просто використовував Guid + ForiegnId.
Jerad,

Відповіді:


77

Якщо ви збираєтеся виконувати будь-яку синхронізацію між базами даних з підключеними програмами, що періодично підключаються, то вам слід використовувати GUID для своїх первинних ключів. Це свого роду біль для налагодження, тому, крім цього випадку, я, як правило, дотримуюся ints, які автоматично збільшуються.

Autoincrement Інтс має бути ваше по замовчуванню, а НЕ використовувати їх повинно бути виправдані.


3
GUID не потрібен, просто змініть крок на 10 або 20 або скільки серверів вам потрібно буде синхронізувати в майбутньому.
Роберт С. Барт,

44
Принаймні у 90% випадків GUID не потрібен і витрачає місце.
Джонатан Леффлер

8
Я серйозно вважаю, що GUID є надмірним. Ніколи ще не було потреби мати GUID в якості своїх основних ключів.
Кирило Гупта

7
Або, замість того, щоб витрачати місце і ризикувати зіткненням з GUID, створіть складений ключ вихідного первинного ключа та малий ідентифікатор, де малий ідентифікатор відрізняється для кожного джерела синхронізації.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

5
Магазин, в якому я працював, використовував GUID для всього, навіть коли були доступні загальнодоступні ідентифікатори, такі як коди країн або мов ISO. І навіть тоді, коли логічного значення чи CHAR(1)цього було б достатньо, як sex. Зайве говорити, що це був кошмар, з яким слід працювати.
Лумі

56

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

Наприклад, у таблиці імен і кодів штатів (США) або ім'я, або код можуть бути первинним ключем - вони складають два різні ключі-кандидати, і один із них (зазвичай коротший - код) вибирається як первинний ключ. У теорії функціональних залежностей (та залежності об'єднання - 1NF до 5NF - ключові кандидати мають вирішальне значення, а не первинний ключ.

Як протилежний приклад, людські імена, як правило, роблять неправильний вибір первинного ключа. Є багато людей, які називаються "Джон Сміт" або деякі інші подібні імена; навіть беручи до уваги імена по батькові (пам’ятайте: це не у кожного - наприклад, у мене немає), є багато можливостей для дублювання. Отже, люди не використовують імена як первинні ключі. Вони вигадують штучні ключі, такі як номер соціального страхування (SSN) або номер працівника, і використовують їх для позначення особи.

Ідеальний первинний ключ - це короткий, унікальний, пам’ятний та природний. З цих характеристик унікальність є обов’язковою; решта повинні згинатися, враховуючи обмеження даних реального світу.

Отже, коли справа доходить до визначення первинного ключа даної таблиці, ви повинні подивитися, що ця таблиця представляє. Який набір чи набори значень стовпців у таблиці однозначно ідентифікує кожен рядок у таблиці? Це ключі-кандидати. Тепер, якщо кожен ключ-кандидат складається з 4 або 5 стовпців, тоді ви можете вирішити, що вони занадто незграбні, щоб зробити хороший первинний ключ (в першу чергу через нестачу). За таких обставин ви можете ввести сурогатний ключ - штучно сформоване число. Дуже часто (але не завжди) для сурогатного ключа достатньо простого 32-бітового цілого числа. Потім ви призначаєте цей сурогатний ключ як первинний ключ.

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

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

У деяких аспектах це досить тверда точка зору.

У мене немає особливих проблем із використанням GUID, коли вони потрібні, але вони, як правило, великі (як у 16-64 байтах), і їх використовують занадто часто. Дуже часто вистачає цілком гарного 4-байтового значення. Використання GUID, де 4-байтового значення вистачить, витрачає дисковий простір і уповільнює навіть індексований доступ до даних, оскільки на одну сторінку індексу менше значень, тому індекс буде глибшим, і потрібно буде прочитати більше сторінок, щоб дістатися до інформація.


10
Щодо вашої вибірки з іменами штатів США, я б віддав перевагу окремому сурогатному ключу, просто тому, що коди є чимось поза вашим контролем. Якщо вони повинні змінитися з будь-якої причини, у вас виникає проблема.
Dirk Vollmar

1
(продовження) Наприклад, Німеччина замінила 4-значну систему поштових індексів на 5-значну систему ще в 1990-х роках після об’єднання.
Dirk Vollmar

@divo: Я є рішучим прихильником штучних / сурогатних ключів, але навіть я не вважаю, що зміна поштового індексу з 4 до 5 цифр є хорошим прикладом. Поштові індекси зазвичай не використовуються як ключі до чогось. (Коли востаннє вам доводилося запитувати таблицю PostalCode, щоб дізнатись щось про цей код? Ні, він майже виключно використовується як частина адреси, без посилання в будь-яких інших таблицях. Я б сказав, що ваша пропозиція майже нарівні з використанням сурогатні ключі для самих адрес.)
ErikE

@Emtucifor: Так, можливо, ZIP - це не дуже практичний приклад, але моя думка полягала в тому, що якщо частина вашого сурогатного ключа виходить з-під вашого контролю і змінюється з будь-якої причини, у вас трапляються проблеми. Подумайте, хтось створює нову схему номерів соціального страхування, нову схему ISSN або - можливо, більш реалістично - компанію, яка вирішила створити нову систему ідентифікації товару після злиття, призначивши номери працівників своїм співробітникам для регулювання їхнього зростання тощо. все лише вигадані приклади, але, як показує мій попередній приклад із ZIP, іноді усталена система може змінитися.
Dirk Vollmar 02

2
Ваш перший пункт правильний. Існує назва цього обмеження. Це називається "цілісність сутності". EI вимагає, щоб кожна сутність мала унікальну ідентичність. Первинні ключі часто відповідають цій вимозі, за винятком випадків, коли використовується автонумерація. З автономером можна отримати два однакові рядки, за винятком автонумерації. Зазвичай це порушує цілісність сутності.
Уолтер Мітті

26

Це лише релігійне питання, оскільки люди шукають універсальної правильної відповіді. Той факт, що ваша команда та цей потік SO демонструє стільки розбіжностей, повинен бути підказкою того, що є вагомі причини використовувати всі описані вами рішення за різних обставин.

  • Сурогатні ключі корисні, коли жоден інший атрибут або набір атрибутів у таблиці не підходить для унікальної ідентифікації рядків.
  • Натуральні клавіші переважні, коли це можливо, щоб зробити стіл зручнішим для читання. Натуральні ключі також дозволяють зовнішньому ключу в залежній таблиці містити реальне значення замість сурогатного ідентифікатора. Наприклад, коли вам потрібно зберегти state(CA, TX, NY), ви можете також використовувати char(2)природний ключ замість int.
  • За необхідності використовуйте складені первинні ключі. Не додавайте " id" сурогатний ключ без необхідності, коли існує цілком хороший складний ключ (це особливо вірно в таблицях "багато до багатьох"). Мандат для триколонного ключа в кожній таблиці є абсолютною дурницею.
  • GUID - це рішення, коли потрібно зберегти унікальність кількох сайтів. Вони також зручні, якщо вам потрібні значення в первинному ключі, щоб бути унікальними, але не упорядкованими чи послідовними.
  • INT проти BIGINT: незвично, що таблиця вимагає 64-бітового діапазону для первинних ключів, але зі збільшенням доступності 64-бітового обладнання це не повинно бути тягарем і дає більше впевненості, що ви не переповнюєтесь. INT, звичайно, менший, тому, якщо космос має премію, це може дати невелику перевагу.

7
Я не згоден настільки, наскільки людина може це зробити. Натуральні ключі жахливі. Що робити, якщо хтось хоче змінити дані? О, ти не можеш. Написати з'єднання на складених природних клавішах - це важка справа. Нести цей складений ключ до всіх пов’язаних таблиць марно.
Роберт К. Барт,

2
@ Роберт: читайте про "ОНОВЛЕНИЙ КАСКАД". Але я розумію те, що ви говорите, і погоджуюсь, що найкраще використовувати сурогатний ключ більшу частину часу, оскільки атрибути можуть змінюватися і бути не унікальними.
Білл Карвін,

2
Первинні ключі повинні бути незмінними. Каскадні оновлення - це лише потворний хак для невдалого дизайнерського рішення в цьому випадку. Натуральні клавіші НІКОЛИ не бажані. Те саме, що і композитні клавіші, які поширюються, як чума. Хто б мав досвід розробки баз даних більше 3 місяців, це знав би.
FDCastel

7
@FD: Я не згоден з вашим однозначним твердженням, і я розробляю бази даних SQL з 1992 року. Але, безумовно, це правда, що сурогатні ключі найкраще можуть залишатися незмінними.
Білл Карвін,

20

Мені подобається блог Програміста баз даних як джерело такої інформації.

3 стовпці для первинного ключа? Я б сказав, що стовпці повинні мати відповідні унікальні обмеження, як того вимагають бізнес-правила, але я все одно маю окремий сурогатний ключ. Складені ключі означають, що в ньому входить бізнес-логіка. Якщо логіка змінюється, вся ваша схема вкручена.


2
Вони змінили своє посилання, ось оновлена ​​закладка: database-programmer.blogspot.com/2008/09/…
Брайан Ребейн

Щойно успадкував такий проект. І найперше, що вони хотіли зробити, підірвало схему. Сурогатні ключі FTW. Бізнес-логіка у вашому DB FTL.
Джейсон


11

Трохи не в темі, але я відчуваю, що змушений поспішати з ...

Якщо ваш первинний ключ є GUID, не робіть його кластерним індексом . Оскільки GUID не є послідовними, дані будуть переупорядковуватися на диску майже під час кожного вставлення. (Погано.) Якщо ви використовуєте GUID як первинні ключі, вони повинні бути некластерованими індексами.


1
Дуже хороший момент - потрібно розрізняти ЛОГІЧНУ концепцію первинного ключа (може бути допустимим використання GUID для цього, особливо якщо задіяна реплікація), та ФІЗИЧНУ концепцію кластерного ключа - це НІКОЛИ не повинно бути GUID, оскільки це призводить до надмірної фрагментації індексу
marc_s

3
Це насправді не точно. Дані будуть вставлені в порядку, що, враховуючи випадковий характер GUID, може опинитися в будь-якому місці таблиці. Якщо не залишиться місця, відбудеться розділення сторінки, але, звичайно, не буде «перевпорядкування на диску під час кожного вставлення», навіть закритого.
Ральф Шиллінгтон,

@Ralph, ти маєш рацію, не КОЖНА вставка, але достатня, щоб викликати 20-кратний показник продуктивності. sql-server-performance.com/articles/per/…
Портман

Функція SQL Server newsequentialid () вирішує проблему фрагментації індексу за допомогою GUID (хоча 24 байти все ще трохи надмірні, якщо вам абсолютно не потрібна глобальна унікальність). Див. Msdn.microsoft.com/en-us/library/ms189786.aspx.
ErikE

10

Я завжди йду із сурогатним ключем. Сурогатний ключ (як правило, стовпець ідентичності, автоінкремент або GUID) - це ключ, у якому ключ відсутній у самих даних. З іншого боку, природний ключ - це той, який сам по собі однозначно ідентифікує рядок. Наскільки я можу сказати в житті, навряд чи є справжні природні ключі. Навіть такі речі, як SSN у США, не є природним ключем. Складені первинні ключі - це катастрофа, яка чекає. Ви не можете редагувати жодної з цих даних (що є основним недоліком будь-якого природного ключа, складеного чи ні), але гірше те, що за допомогою складеного ключа тепер вам доведеться увічнити ці ключові дані у кожній пов'язаній таблиці. Які гігантські відходи.

Тепер для вибору сурогатного ключа я дотримуюся стовпців ідентифікаційних даних (я працюю переважно в MS SQL Server). GUID занадто великі, і Microsoft рекомендує не використовувати їх як ПК. Якщо у вас кілька серверів, все, що вам потрібно зробити, це збільшити 10 або 20 або, як ви вважаєте, максимальна кількість серверів, яку вам коли-небудь знадобиться синхронізувати / розширити, і просто включити насіння для кожної таблиці на кожному наступному сервері , і у вас ніколи не буде зіткнення даних.

Звичайно, через збільшення я роблю стовпець ідентифікатора BigInt (інакше відомий як довгий [64 біти]).

Виконуючи трохи математики, навіть якщо ви зробите приріст 100, у вашій таблиці все одно може бути 92 233 720 368 547 758 (> 92 квадрильйони) рядків.


9

Я думаю, що використання слова "Первинний" у фразі "Первинний" ключ у реальному сенсі вводить в оману.

По-перше, використовуйте визначення, що "ключ" - це атрибут або набір атрибутів, які повинні бути унікальними в таблиці,

Тоді наявність будь-якого ключа служить для кількох часто взаємно несумісних цілей.

  1. Використовувати як умови об’єднання для одного або багатьох записів у дочірніх таблицях, які мають відношення до цієї батьківської таблиці. (Явне або неявне визначення зовнішнього ключа в цих дочірніх таблицях)
  2. (пов’язано) Забезпечення того, що дочірні записи повинні мати батьківський запис на батьківській вкладці; e (дочірня таблиця FK повинна існувати як ключ у батьківській таблиці)
  3. Для збільшення перфорамності запитів, яким потрібно швидко знайти певний запис / рядок у таблиці.

  4. Щоб забезпечити узгодженість даних, запобігаючи вставленню в таблицю повторюваних рядків, що представляють одну і ту ж логічну сутність. (Це часто називають "природним" ключем, і він повинен складатися з атрибутів таблиці (сутності), які є відносно незмінними.)

Очевидно, що будь-який несуттєвий, неприродний ключ (наприклад, GUID або автоматично згенероване ціле число) абсолютно не здатний задовольнити # 4.

Але часто у багатьох (більшості) таблиць абсолютно природний ключ, який може надати номер 4, часто складається з декількох атрибутів і буде надмірно широким або настільки широким, що використання його для цілей №1, №2 чи №3 спричинить неприйнятність наслідки продуктивності.

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

Щодо GUID, будьте дуже обережні, використовуючи їх, оскільки використання напрямних в індексі може спричинити фрагментацію індексу. Найпоширеніші алгоритми, що використовуються для їх створення, ставлять "випадкову" частину направляючого в найбільш значущі бітові позиції ... Це збільшує вимогу до регулярної дефрагментації індексу / повторного індексування при додаванні нових рядків.


Функція SQL Server newsequentialid () вирішує проблему фрагментації індексів GUID (хоча 24 байти все ще трохи надмірні, якщо вам абсолютно не потрібна глобальна унікальність). Див. Msdn.microsoft.com/en-us/library/ms189786.aspx.
ErikE

ой, я хотів сказати 16 байт.
ErikE

8

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

Я працював в одному місці, де первинним ключем був ідентифікатор рахунку, який являв собою комбінацію літер і цифр. Я не пам’ятаю жодної специфіки, але, наприклад, ті рахунки, які були певного типу, були б у діапазоні 600, а іншого типу, починалися з 400. Це було чудово, поки той клієнт не вирішив попросити обидва види робіт. Або змінили тип роботи, яку вони виконували.

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

Cat1.subcatA.record1
Cat1.subcatA.record2
Cat1.subcatB.record1
Cat2.subcatA.record1

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

Будь ласка, будь ласка, будь ласка, якщо ви пишете код, який мені коли-небудь доводилося підтримувати, будь ласка, не використовуйте розумний ключ!


Я згоден всією душею. Розумні клавіші = німі.
Роберт К. Барт,

2
Це не означає, що природні клавіші німі. Але хороший момент.

4

Я прихильник автоматичного збільшення як первинного ключа. Я глибоко в глибині свого серця знаю, що це копія, але це дозволяє настільки легко сортувати дані за часом їх додавання (ЗАМОВИТИ ЗА ІДЕНТИФІКАЦІЄЮ, наприклад, наприклад).

3 колонки звучать по-людськи розбір жахливо різко.

І це компроміс - скільки реляційних можливостей вам потрібно, порівняно з тим, щоб зробити ЦЮ ТАБЛИЦУ ПРАВИЛЬНО ТУТ зрозумілою для людини, яка її допитує (проти збереженої процедури або програмного інтерфейсу).

автоматичне збільшення - це для нас, людей. :-(


4

Як правило, це залежить.

Особисто мені подобаються автоінкременти.

Але одне, що я можу вам сказати, це ніколи не довіряти дані з інших джерел як ваш ключ. Клянусь, кожен раз, коли я це роблю, воно повертається, щоб мене вкусити. Ну, ніколи більше!


3

Має бути принаймні 3 стовпці, що складають первинний ключ.

Я цього не розумію.

Ви говорите про "природний ключ", наприклад, "ім'я та дата народження"? Натуральний ключ може бути ідеальним, якщо він існує, але більшість кандидатів на природний ключ або не є унікальними (кілька людей з однаковим ім’ям), або не є постійними (хтось може змінити своє ім’я).

Int / BigInt, які автоінкременти є досить хорошими первинними ключами.

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


Первинні ключі повинні бути унікальними, але не повинні бути постійними. Звідси іноземні ключі, декларовані за допомогою "ON UPDATE CASCADE". Але припущення про постійність первинних ключів сприяє спрощенню багатьох програм. Це одна перевага сурогатних ключів.
Білл Карвін,

3

RE GUID

Слідкуйте, чи це буде дійсно ДІЙСНО ДІЙСНО велика база даних, велика кількість навантаження та швидкий доступ.

На моїй останній роботі, де у нас було баз даних від 100 до 500 мільйонів записів, хлопці з нашої бази рішуче сперечались проти GUID і за десяткове число відповідного розміру. Вони відчували, що (за Oracle) різниця розмірів у внутрішній пам’яті для рядка Guid - проти десятичного значення зробить дуже помітну різницю в пошуку. (Більші ключі = глибші дерева для обходу)

Випадковий характер GUID також значно зменшує коефіцієнт заповнення сторінок індексу - це різко збільшує розрив та введення / виведення диска.


"Зменшує коефіцієнт заповнення"? Не впевнений, що це може означати коефіцієнт заповнення - це одноразова угода, що визначається як відсоток вільного простору, що вимагається на рівні листа індексу на момент побудови індексу. Значення GUID шляхом їх випадкового розподілу за характером по ширині рівня аркуша на вставках у той вільний простір, який забезпечував коефіцієнт заповнення.
Ральф Шиллінгтон,

1
З якого часу GUID є рядком? GUID повинні зберігатись у внутрішній формі як 16 байт будь-якою респектабельною СУБД. Зберігати як 32 байти в шістнадцятковому поданні було б недобросовісно! (або 36 з тире, або 38 з фігурними дужками)
Ерік 02

2

Стовпці автоматичного збільшення. Я можу змусити свій код працювати безперешкодно з SQL Server або Oracle, один з яких використовує ідентичність, а другий використовує послідовності через мій DAL, і я не міг бути щасливішим. Я згоден, GUID іноді необхідні, якщо ви виконуєте реплікацію або відправляєте дані, щоб отримати їх пізніше при подальшій обробці.


2

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

  • Послідовність
  • Дані незалежні (унікальні, не знищені змінами формату)
  • Людочитабельність

... і немає розумних причин, щоб не:

  • Неоднозначність у приєднаннях? - Згладжування таблиць - краща практика, ІМХО
  • Оптимальні таблиці? - Видалення одного байта за запис - це передчасна оптимізація, IMHO
  • Рішення за столом? - Більше не узгоджується
  • Проблеми з масштабуванням? - Так? Чому?
  • Ієрархічна структура даних? - Це денормалізація, цілий інший предмет релігії. Досить сказати, що я фанат у кількох обставинах теоретично, але ніколи на практиці :)

розумні причини, про які я ще не думав і не стикався, завжди вітаються ...


1

Це класика "це залежить". Для кожного проекту немає однієї правильної відповіді. Мені подобаються різні речі для різних ситуацій. Це залежить від того, чи використовую я ORM і що він підтримує. Це залежить від загальної архітектури (розподіленої чи ні тощо). Просто виберіть той, який, на вашу думку, буде працювати, і перейдіть до суперечок щодо вкладок та пробілів.


Він все ще бажає знати, ЯК це залежить; лише усвідомлюючи це, можна довіряти самому вибирати ...
Ніколас Леонард

1

Я, як правило, використовую варіант №1 або №3 залежно від розміру, кількості людей, які підключаються, і чи це ситуація на сервері декількох баз даних чи ні.

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


1

Я використовую лише автоматичне збільшення int або GUID. 99% часу я використовую автоматичне збільшення int. Це просто те, що мене навчили використовувати, коли я вперше дізнався про бази даних і ніколи не стикався з причиною їх не використовувати (хоча я знаю причини, чому GUID був би кращим).

Мені подобається автоматичне збільшення ints, тому що це допомагає читати. Наприклад, я можу сказати "подивіться на запис 129383", і комусь досить легко зайти і знайти його. З GUID це майже неможливо зробити.


2
Чому ти це кажеш? Здається, багато людей використовують ціле число з автоматичним збільшенням. Не може бути так погано, якщо це працює і працює добре для того, що вам потрібно.
dtc 02

1

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

  • Чи не є визначення первинного ключа надмірно складним? Чи не уникає це внесення зайвої складності задля дотримання "найкращої практики"?
  • Чи існує кращий можливий первинний ключ, який потребує менших накладних витрат для обробки бази даних (тобто INTEGER проти VARCHAR тощо)?
  • Я АБСОЛЮТНО впевнений, що унікальність та визначеність інваріанта мого первинного ключа не зміниться?

Цей останній, ймовірно, притягує більшість людей до використання таких речей, як GUID або самозростаючі цілочисельні стовпці, тому що, покладаючись на такі речі, як адреси, номери телефонів, імена / прізвища тощо, просто не вирізайте це. Єдиний інваріант людей, про яких я можу думати, - це SSN, але тоді я навіть не впевнений на 100% щодо тих, хто залишається назавжди унікальним.

Сподіваємось, це допомагає додати ясності ...


Є кілька історичних випадків, коли SSN не є унікальними.
Білл Карвін,

1

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


Чи означає це, що ви "уникаєте автоматичного збільшення цілих чисел, коли тільки можете"? Я зрозумів, що галузеві експерти вважають, що найкраща продуктивність великомасштабних баз даних відбувається завдяки мінімально підписаним індексованим інкрементальним одноколонним ПК.
Hardryv

1
Я завжди думав, що експерти використовували найкращий інструмент для роботи
Ендрю Г. Джонсон,

1

Майже завжди цілі числа.

У них є й інші вагомі причини, крім того, що їх менше / швидше обробляти. Що ви воліли б записати - "404040" чи "3463b5a2-a02b-4fd4-aa0f-1d3c0450026c"?


Останнє може бути цілим числом, з доданими тире та в основі 16. Але так, 404040 обробляється швидше, ніж довгий GUID. Знову ж таки, 0 ще швидше обробляється, тому що для цього не потрібно жодного біта даних!
Strager 01

1

Тільки трохи релевантно, але одне, що я почав робити нещодавно, коли маю невеликі класифікаційні таблиці (по суті, ті, що представляють ENUM в коді), це те, що я зроблю первинний ключ char (3) або char (4). Потім я роблю ці первинні ключі репрезентативними для значення пошуку.

Наприклад, у мене є система котирування для наших внутрішніх торгових агентів. У нас є "Категорії витрат", кожному позиції котирування присвоюється одна з ... Отже, у мене є таблиця пошуку типу "tCostCategories", де первинним ключем є "MTL", "SVC", "TRV", "TAX", 'ODC'. Інші стовпці в таблиці пошуку містять більше деталей, таких як звичайні англійські значення кодів, "Матеріал", "Сервіс", "Подорожі", "Податки", "Інші прямі витрати" тощо.

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

1 PartNumber $ 40 MTL
2 OtherParNumber $ 29,99 SVC
3 PartNumber2 $ 150 TRV

Набагато простіше, якщо використовувати int для представлення категорій, а потім зв’язати 1, 2, 3 у всіх рядках - у вас є дані прямо перед собою, і продуктивність, здається, не постраждала зовсім (не те, що я ' я справді перевірений.)

Що стосується справжнього питання ... Мені подобаються унікальні ідентифікатори RowGUID. Я не на 100% з цього, але чи не всі рядки мають внутрішні RowGuid все одно ?? Якщо так, тоді використання RowGuid насправді займе менше місця, ніж ints (або що-небудь ще з цього приводу.) Мені відомо лише те, що якщо для M $ це достатньо для використання у GreatPlains, то для мене це досить добре. (Чи слід качати ??)


1

О ще одна причина, через яку я використовую GUID - я використовую ієрархічну структуру даних. Тобто, у мене є таблиця «Компанія» та таблиця «Постачальник», для яких збігаються Основні ключі. Але у мене також є таблиця "Виробник", яка також "успадковується" від компанії. Поля, загальні для Постачальників та Виробників, не відображаються в цих таблицях - вони з’являються в Компанії. У цьому налаштуванні використання int набагато болючіше, ніж Guids. Як мінімум, ви не можете використовувати первинні ключі ідентичності.


1
Так, ви можете, ви просто не робите таблиці підтипів властивістю ідентичності, натомість вони отримують явні вставки значення таблиці супертипу. Будь ласка , см stackoverflow.com/questions/2112882 / ...
ErikE

1

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

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

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

Як зазначали інші, термін "первинний ключ" трохи вводить в оману. У Реляційній моделі даних використовується термін "ключові кандидати". Для однієї таблиці може бути кілька ключів-кандидатів. Логічно, що кожен з них настільки ж гарний, як і інший. Вибір одного з них як "основного" та здійснення всіх посилань за допомогою цього ключа - це просто вибір дизайнера.


Будь ласка, опишіть деякі зразки надійних природних ключів?
ErikE

1
"надійний" сам по собі не є властивістю ключа. Швидше, це пов’язано з ключем у контексті людей, які надають дані. Якщо ви пишете програму для продажу комусь, хто насправді буде керувати даними, вам слід здогадатися, які ключі будуть надійними для клієнта чи ні. З огляду на різноманітність клієнтів, ви майже напевно збираєтеся вгадати неправильно для певної частини своєї клієнтури.
Уолтер Мітті

Сказавши вище, ось приклад ключа, якому ми довіряли ще колись. У нас була база даних про курси. Він включав підручники та інші навчальні матеріали про курси, заплановані курсові пропозиції, викладачів, які мали кваліфікацію для викладання курсів, передумови курсу, навчання тощо. Коли розробка курсів створила новий курс, однією з перших справ, яку вони зробили, було призначення коду курсу. Вони несли відповідальність за те, щоб коди курсів були унікальними, і щоб курси ніколи не змінювали свій код, коли вони були призначені. Це була частина даних, наданих нам.
Уолтер Мітті

Ще одним хорошим прикладом надійного природного ключа є VIN (ідентифікаційний номер транспортного засобу). Протягом останніх багатьох років на кожному транспортному засобі, що продається як новий, до нього прикріплений VIN. Їм можна довірити, що вони унікальні та незмінні.
Уолтер Мітті

1

Керівництво. Період.

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


оновлення, щоб пояснити моє твердження.

Я працював на багатьох різних сайтах. Від малих одиничних серверних угод до великих, підтриманих кількома БД та веб-серверами. Звичайно, були додатки, які були б чудовими з автоматичним збільшенням ints як первинних ключів. Однак це не відповідає моделі того, як я роблю речі.

Використовуючи GUID, ви можете генерувати ідентифікатор де завгодно. Він може бути згенерований віддаленим сервером, вашою веб-програмою, в самій базі даних або навіть у декількох базах даних у мультимайстерній ситуації.

З іншого боку, автоматично збільшений INT може бути безпечно сформований лише в межах первинної бази даних. Знову ж таки, це може бути нормально, якщо у вас є програма, яка буде тісно пов’язана з цим резервним сервером БД, і масштабування вас не стосується.

Звичайно, використання GUID означає, що ви повинні мати щоночні процеси переіндексації. Однак, якщо ви використовуєте що-небудь, крім автоматично збільшеного INT, ви все одно повинні це зробити. Чорт, навіть якщо INT є основним, швидше за все, у вас є інші індекси, які потребують регенерації, щоб мати справу з фрагментацією. Тому використання GUID не точно додає іншої проблеми, оскільки ці завдання потрібно виконувати незалежно.

Якщо ви подивитесь на великі програми там, ви помітите щось важливе: усі вони використовують ключі, закодовані в Base64. Причина цього проста, використання GUID дозволяє легко масштабувати , тоді як при спробі масштабування INT може бути багато обручів, які можна перестрибнути.

Наш останній додаток переживає період важких вставок, який триває близько місяця. Після цього 90 +% запитів - це всі вибірки для звітності. Для збільшення ємності я можу підняти додаткові сервери БД протягом цього великого періоду вставки; а згодом легко об’єднати їх в одну БД для звітності. Спроба зробити це за допомогою ІНТ була б абсолютним кошмаром.

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


Ви коли-небудь вивчали коефіцієнт заповнення своїх індексів? Випадковість GUID робить з них швейцарський сир - різко знижує їх ефективність.
stephbu

2
"Guids.period": Це дуже неправильно. За необхідності слід використовувати GUID. Як зазначав інший коментатор, це може полегшити життя програміста, але впливає на загальний розмір і продуктивність БД.
Mitch Wheat

Врешті-решт я можу без проблем масштабувати свої програми на декількох серверах баз даних. Але, мабуть, ви, хлопці, працюєте на невеликих сайтах.
NotMe 02

3
GUID може бути нормальним для логічного первинного ключа, але НІКОЛИ НІКОЛИ НІКОЛИ не використовуйте стовпець GUID як ваш кластерний ключ - ви будете тонути в фрагментації індексів, що призведе до
БІДНОЇ

Я точно не оголошував би "Guids.period". на цю тему - насправді навіть у такій галузі, яка наповнена `` найкращими практиками '', подібні твердження за замовчуванням ставлять вас на хитку землю (особливо з цим твердженням). Все, з чим болісно мати справу, як GUID, потребує жорсткого обґрунтування, і, як каже JL, я думаю, більшість з нас вважатиме це крайнім засобом. Це так, ніби ви розмістили повідомлення, не прочитавши решту теми.
Hardryv

0

Це складна тема, усвідомлювали ви це чи ні. Можливо, підпадає під розділ цього Поширеного запитання про StackOverflow.

Які запитання мені тут не задавати?

Уникайте питань, які є суб’єктивними, аргументованими або вимагають тривалого обговорення. Це місце для питань, на які можна відповісти!

Про це роками дискутують і будуть дискутувати роками. Єдиний натяк на консенсус, який я бачив, полягає в тому, що відповіді є дещо передбачуваними, залежно від того, запитуєте ви хлопця з ОО (GUID - це єдиний шлях!), Модельєра даних (природні ключі - це єдиний шлях!) або DBA, орієнтована на продуктивність (INT - єдиний шлях!).


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

1
Я кажу, задайте будь-які запитання, які хочете! В іншому випадку ця спільнота стане статичною і надконтрольованою, як, здається, стала Вікіпедія. Мені здається, що деколи потрібно дозволяти людям запитувати все, що вирішили запитати. Довіряйте їм, і вони можуть прийти довіряти собі!
Ніколас Леонард
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.