складені первинні ключі - це погана практика? [зачинено]


15

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

Моє запитання засноване на цій статті

помилки проектування баз даних

Частина про складені первинні ключі:

Погана практика № 6: Складені первинні ключі

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

Зображення складеного первинного ключа

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

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


4
Це не "хороша" чи "погана" практика. Кожне дизайнерське рішення повинно слугувати меті; якщо ви можете пояснити (собі та іншим), чому вам потрібен складений ПК, ви добре піти. І навпаки, якщо ви можете пояснити, чому він вам не потрібен, ви також добре піти. Стаття, на яку ви посилаєтесь, робить дуже погану роботу, пояснюючи, на мій погляд.
mustaccio

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

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

1
Наскільки GUID кращий, ніж INTEGER [Серійний | Auto_Increment | Ідентичність | <що б то не було_повноваження>]?
Vérace

4
Я б не наймав цього автора
папараццо

Відповіді:


31

Сказати, що використання - "Composite keys as PRIMARY KEY is bad practice"це сувора нісенітниця!

Композиція PRIMARY KEYчасто - це дуже "добра річ" і єдиний спосіб моделювати природні ситуації, що трапляються в повсякденному житті!

Подумайте про класичний приклад баз даних-101 для студентів та курсів та про безліч курсів, які проходять багато студентів!

Створіть таблицю курсу та студента:

CREATE TABLE course
(
  course_id SERIAL,
  course_year SMALLINT NOT NULL,
  course_name VARCHAR (100) NOT NULL,
  CONSTRAINT course_pk PRIMARY KEY (course_id)
);


CREATE TABLE student
(
  student_id SERIAL,
  student_name VARCHAR (50),
  CONSTRAINT student_pk PRIMARY KEY (student_id)
);

Я наведу вам приклад в діалекті PostgreSQLMySQL ) - повинен працювати на будь-якому сервері, який трохи налаштовує.

Тепер ви, очевидно, хочете відслідковувати, який студент проходить який курс - так у вас є те, що називається joining table(також називається linking, many-to-manyабо m-to-nтаблиці). Вони також відомі як associative entitiesу більш технічному жаргоні!

1 курс може мати багато студентів.
1 студент може пройти багато курсів.

Отже, ви створюєте таблицю приєднання

CREATE TABLE course_student
(
  cs_course_id INTEGER NOT NULL,
  cs_student_id INTEGER NOT NULL,

  -- now for FK constraints - have to ensure that the student
  -- actually exists, ditto for the course.

  CREATE CONSTRAINT cs_course_fk FOREIGN KEY (cs_course_id) REFERENCES course (course_id),
  CREATE CONSTRAINT cs_student_fk FOREIGN KEY (cs_student_id) REFERENCES student (student_id)
);

Тепер єдиний спосіб розумно дати цій таблиці PRIMARY KEY- KEYце поєднання курсу та студента. Таким чином, ви не можете отримати:

  • дублікат комбінації студентів та курсів

    • на курс може бути записаний той самий студент лише один раз, і

    • студент може записатися на той самий курс лише один раз

  • у вас також є готовий пошук KEYкурсів на одного студента - AKA показник покриття ,

  • Неважливо знайти курси без студентів та студентів, які не беруть курсів!

    - ДБ-скрипці приклад має обмеження PK складене в CREATE TABLE - Це може бути зроблено в будь-якому випадку. Я вважаю за краще, щоб все було у викладі CREATE TABLE.


ALTER TABLE course_student 
ADD CONSTRAINT course_student_pk 
PRIMARY KEY (cs_course_id, cs_student_id);

Тепер ви могли б, якби виявили, що пошук студента за курсом повільний, скористатися UNIQUE INDEXфункцією on (sc_student_id, sc_course_id).

ALTER TABLE course_student 
ADD CONSTRAINT course_student_sc_uq  
UNIQUE (cs_student_id, cs_course_id);

Там немає ні срібної кулі для додавання індексів - вони будуть робити INSERTз і UPDATES повільніше, але на великий зиск надзвичайно убутніSELECT раз! Розробник повинен вирішити індексувати, враховуючи свої знання та досвід, але сказати, що композитні PRIMARY KEYs завжди погані, це просто неправильно.

У випадку приєднання таблиць вони, як правило, єдині, PRIMARY KEY що мають сенс! Приєднання до столів також дуже часто є єдиним способом моделювання того, що відбувається в бізнесі чи природі чи практично у будь-якій сфері, про яку я можу придумати!

Цей ПК також використовується в якості covering indexзасобу, який може допомогти прискорити пошук. У цьому випадку було б особливо корисно, якби хтось регулярно здійснював пошук на (course_id, student_id), що, можна було б уявити, часто може бути!

Це лише невеликий приклад того, де композит PRIMARY KEYможе бути дуже хорошою ідеєю і єдиним розумним способом моделювання реальності! Я маю на увазі ще багато інших.

Приклад з моєї власної роботи!

Розгляньте таблицю польотів, що містить переліт_id, перелік аеропортів вильоту та прибуття та відповідні часи, а потім також таблицю екіпажних кабін з членами екіпажу!

Тільки розумний спосіб це може бути змодельоване, щоб мати таблицю flight_crew з flight_id і crew_id як і атрибути оголошення єдиними розумними PRIMARY KEY, щоб використовувати складовою ключ з двох полів!


2
на прикладі курсу та студентів, чи можливо, що для курсу_student є idяк первинний ключ, так і унікальний індекс cs_student_id cs_course_idта мають однакові результати?
hackvan

2
Навіщо витрачати ресурси на це? З PK (course_id, student_id) за визначенням у вас вже є унікальний індекс цих полів! Унікальний індекс на (student_id, course_id) може бути корисним для прискорення пошуку - скажімо, якщо ви шукали студентів, які не відвідували жодного курсу, але це рішення може бути оперативним, але в ці дні відносно дешевого зберігання, Я б рекомендував це, тим більше, що можна подумати, що таблиця не буде оновлюватися дуже часто.
Vérace

1
Погодьтесь повністю для таблиць посилань - я зараз працюю з кількома. Однак, коли я надягаю шапку C #, я працюю з генератором reversepoco та створюю корисні класи (знайти, зберегти тощо) для наступного шару вгору. У мене виникла головна проблема - складові ключі стають PITA за те, щоб мати будь-який загальний код збереження / пошуку. Так, можливо, я міг би повернутися до файлів EDMX, але мені все одно потрібно обійти або спеціальний код справи (рахувати стовпці Pkey?), Або додати штучний сурогатний ключ (не подобається і потрібні додаткові обмеження унікальності :(). люди не люблять композити, говорять із коду шару додатків.
Річард Гриффітс

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

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

3

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

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

Microsoft SQL Server має чітку, але пов'язану з цим функцію "кластерного індексу", який контролює фізичне зберігання даних у порядку індексу, а також використовується всередині інших індексів. За замовчуванням первинний ключ створюється як кластерний індекс, але ви можете вибрати некластеризований замість цього, бажано після створення кластерного індексу. Таким чином, ви можете мати цілочисленний ідентифікаційний стовпець як кластерний індекс, і, скажімо, ім'я файлу nvarchar (128 символів) в якості основного ключа. Це може бути краще, тому що кластерний індексний ключ вузький, навіть якщо ви зберігаєте ім'я файлу як термін іноземного ключа в інших таблицях, хоча цей приклад є гарним випадком, коли це також не робити.

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

https://www.techopedia.com/definition/5547/primary-key описує приклад вибору того, чи потрібно зберігати дані з номером соціального страхування клієнта як ключ клієнта у всіх таблицях даних, або генерувати довільний customer_id, коли ви зареєструйте їх. Насправді це серйозне зловживання SSN, окрім того, працює він чи ні; це особисте та конфіденційне значення даних.

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

Крім того, у вас виникають проблеми, якщо SSN або інший ключ даних був записаний неправильно, тому ви маєте неправильне значення у 20 обмежених таблицях замість лише в "Клієнт". Тоді як синтетичний customer_id не має зовнішнього значення, тому він не може бути неправильним значенням.


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