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


18

У межах однієї веб-програми, над якою я працюю, всі операції з базою даних абстрагуються за допомогою деяких загальних сховищ, визначених через Entity Framework ORM.

Однак для того, щоб мати просту конструкцію для загальних сховищ, усі залучені таблиці повинні визначати унікальне ціле число ( Int32у C #, intу SQL). Досі це завжди було ПК таблиці, а також IDENTITY.

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

Прикладний рівень зазвичай виконує такі операції:

  • початкове завантаження даних з таблиці (*) -SELECT * FROM table
  • Оновлення -UPDATE table SET Col1 = Val1 WHERE Id = IdVal
  • Видалити -DELETE FROM table WHERE Id = IdVal
  • Вставити -INSERT INTO table (cols) VALUES (...)

Рідше операції:

  • Об'ємна вставка - BULK INSERT ... into tableсупроводжується (*) всім завантаженням даних (для отримання створених ідентифікаторів)
  • Масове видалення - це звичайна операція видалення, але "об'ємна" з точки зору ORM:DELETE FROM table where OtherThanIdCol = SomeValue
  • Масове оновлення - це звичайна операція оновлення, але "об'ємна" з точки зору ORM:UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue

* всі невеликі таблиці кешуються на рівні програми і майже всі SELECTsне доходять до бази даних. Типовою схемою є початкове навантаження та велика кількість INSERTs, UPDATEs та DELETEs.

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

Запитання: З точки зору DBA, чи є серйозні проблеми, з якими я можу зіткнутися через обмеження в дизайні таблиці?

[EDIT]

Прочитавши відповіді (дякую за чудові відгуки) та посилання на статті, я відчуваю, що мені потрібно додати більше деталей:

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

  2. "вони не повинні бути єдиним способом однозначно визначити ряд" (Аарон Бертран ♦) - це дуже хороша порада. Усі мої таблиці також визначають УНІКАЛЬНЕ ОБМЕЖЕННЯ, щоб переконатися, що копії бізнесу не дозволені.

  3. Дизайн, керований додатком та дизайном, керований базами даних - вибір дизайну обумовлений цими чинниками

    1. Обмеження Entity Framework - кілька ПК у стовпцях дозволено, але їх значення не можна оновити

    2. Спеціальні обмеження - наявність єдиного цілого ключа значно спрощує структури даних та не-SQL-код. Напр .: усі списки значень мають цілий ключ та відображені значення. Що ще важливіше, це гарантує, що будь-яку таблицю, позначену для кешування, можна буде помістити у Unique int key -> valueкарту.

  4. Складні запити вибору - цього майже ніколи не відбудеться, оскільки всі невеликі (<20-30K записів) таблиці таблиць кешуються на рівні програми. Це робить життя трохи складніше при написанні коду програми (складніше писати LINQ), але база даних потрапляє набагато приємніше:

    1. Перегляди списку - не SELECTзавантажуватиме запитів під час завантаження (усе є кешованим) або запитів, які виглядають так:

      SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)

      Усі інші необхідні значення отримуються через пошук кешу (O (1)), тому складні запити не будуть генеровані.

    2. Редагувати представлення даних - генерувати SELECTтакі заяви:

      SELECT allcolumns FROM BigTable WHERE PKId = value1

(усі фільтри та значення ints)


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

Відповіді:


19

Крім додаткового простору на диску (і, в свою чергу, використання пам'яті та вводу / виводу), насправді немає жодної шкоди для додавання стовпця ІДЕНТИЧНОСТІ навіть до таблиць, які не потребують такої (приклад таблиці, яка не потребує стовпця ІДЕНТИЧНОСТІ) - це проста таблиця переходу, наприклад, зіставлення користувача до його дозволів).

Я заперечую проти того, щоб сліпо додавати їх до кожної таблиці в блозі з 2010 року:

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


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

Я думаю, що існують випадки, які вимагають уникнути перевірки унікальності природних ключів. Як хтось, хто працює з даними ГІС, той, що відразу приходить на думку, - це той, де природним ключем є лише сама геометрія або геометрія плюс якийсь зовнішній ключ. Розшукувати речі за точною геометрією завжди буде непрактично, тому унікальність обмеження на цьому навряд чи багато допоможе та може мати недоліки в роботі. Те ж саме може бути правдою, якщо частина природного ключа - це довгий текстовий стовпець. Але я згоден: коли це практично, так, слід застосовувати унікальне обмеження щодо природного ключа.
jpmc26

13

З мого досвіду, головна і переважна причина використання окремого ідентифікатора для кожної таблиці полягає в наступному:

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

Тоді, з точки зору DBA, речі, які роблять БД повільним або роздутим, - це, звичайно, не 4 байти (або що завгодно) у рядку, але такі речі, як неправильні чи відсутні індекси, забуті перебудови таблиці / індексу, неправильні параметри настройки RAM / таблиці. , нехтуючи використанням змінних прив'язки тощо. Вони можуть уповільнити БД коефіцієнтами 10, 100, 10000 ... не додатковий стовпець ідентифікатора.

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

Примітка: зауважте, що вам не потрібен окремий ідентифікатор для n:mтаблиць асоціацій, оскільки для таких таблиць ідентифікатори асоційованих об'єктів повинні утворювати первинний ключ. Контрприклад - це дивна n:mасоціація, яка дозволяє безліч асоціацій між тими ж двома сутностями з будь-якої химерної причини - їм тоді потрібен власний стовпець ідентифікатора, щоб створити ПК. Там є ОРЗ бібліотеки , які не можуть обробляти первинні ключі декількох стовпців , хоча, так що буде привід бути поблажливим з розробниками, якщо вони повинні працювати з такою бібліотекою.


2
"дивна асоціація n: m, яка дозволяє безліч асоціацій між тими самими двома об'єктами" ДУЖЕ поширені в реальному житті. Наприклад, людина володіє автомобілем, тоді вимоги змінюються, щоб відновити, коли право власності розпочалося та закінчилося ((людина може продати машину та придбати її згодом, а також
зірвати

Так, @IanRingrose.
AnoE

6

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

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

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


1
І все ж у багатьох системах є синтетичні цілі цілі первинних ключів на кожному столі (наприклад, майже кожен додаток Ruby on Rails, написаний коли-небудь), не страждаючи від таких проблем. Вони також ніколи не страждають від проблеми необхідності натискання змін на первинні ключі (які ніколи не мали відбуватися) до всіх таблиць іноземних ключів.
Девід Олдрідж

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

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

5

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

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

Я б сказав, що ціле ПК не збирається вас кусати, якщо ви не плануєте об'єднати дані з окремих джерел або у вас можуть бути дані, що виходять за рамки ваших цілих розмірів - це все весело та ігри, поки у вас не залишиться місця для вставок .

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


2
Здається, як жахливе виправдання змінити всі ключі до посібників. Зараз я працюю з базою даних, яка використовує путівники для всіх сурогатних ключів. Це не весело.
Енді

2
Ні. Використання GUID не є цікавим. Мені це не подобається, але я поважаю їхню цінність у певних випадках використання.
CaM

2

Відклавши:

  • Релігійні війни (сурогат Google проти природного ключа)
  • Окреме питання про те, які кластерні індекси визначити у ваших таблицях
  • Життєздатність кешування всіх ваших даних

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


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

Для грамотного, оптимізованого SQL я згоден, але я мав на увазі можливі обмеження SQL-генераторів. Мій єдиний досвід у цій галузі просять створити обширні погляди, з якими EF можна годувати ложкою - хоча можливо, що .net devs недостатньо знав про EF, або, що були інші причини.
TH

@AaronBertrand Я б сказав, що єдиний спосіб, коли вони можуть бути ефективнішими, це якщо об'єднання взагалі не було потрібне. Я вважаю, що використання природних ключів я маю лише зі стандартними списками кодів, такими як коди валют ISO4127 (які можуть бути впізнавані людиною), і я можу використовувати GBP, EUR тощо як іноземний ключ до первинного або альтернативного ключа валютного коду стіл.
Девід Олдрідж

@David Звичайно, я говорив про випадки, коли приєднання необхідні. Є дуже багато випадків, коли я не хочу, щоб природний ключ поширювався у всіх пов’язаних таблицях, тому що природні ключі можуть змінюватися, і це болісно.
Аарон Бертран

Гммм, я бачу, як мою відповідь можна було неправильно зрозуміти, що рекламують природні закордонні ключі над сурогатними. Щоб було зрозуміло, я насправді згадував їх лише тому, що: а) я читав питання Олексія як "це проблема, що ми не використовуємо природні ключі?"; Б) питання про завершення роботи Олексія починалося з "з точки зору DBA", і я Я вважаю, що я повинен визнати, що існує більше, ніж одна точка зору, і c) тому що я думаю, що використовувані функції ORM значною мірою диктують вибір (якщо це насправді може змінити значення). Я сам твердо перебуваю в сурогатному таборі іноземних ключів.
TH

2

У вас є кілька факторів, які допоможуть вам орієнтуватися,

  1. Визначення та специфікація.

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

  2. Унікальність.

    Для особистої розумності, приєднання та функціонування бази даних вищого рівня вам знадобиться: (a) унікальний стовпець, (b) унікальна серія стовпців

    Усі досить нормалізовані схеми (1NF) забезпечують одне з наступних. Якщо їх немає, ви завжди повинні їх створювати. Якщо у вас є рейтинг людей, призначених на волонтерську неділю, і він включає прізвище та ім'я, ви хочете дізнатися, коли у вас є два Джо Бобса.

  3. Впровадження та оптимізація.

    Int має тенденцію бути невеликою формою даних, яка швидка для порівняння та рівності. Порівняйте це з рядком Unicode, порівняння якого може залежати від місцевості (місця та мови). Збереження 4242 в рядку ASCII / UTF8 - 4 байти. Зберігаючи його як ціле число, воно вміщується в 2 байти.

Отже, якщо мова йде про мінуси, у вас є кілька факторів.

  1. Плутанина і неоднозначність.

    1. Запис блогу @Aaron Bertrand підсумовує це добре. Це не самодокументування, щоб мати OrderID за специфікацією та завданням, а потім накладати " OrderID " через реалізацію бази даних. Іноді доводиться уточнити це або створити конвенцію, але це, ймовірно, додасть плутанини.
  2. Космос.

    Цілі особи все ще додають простір до рядка. І якщо ви не використовуєте їх, немає ніякої мети.

  3. Кластеризація.

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


Приємні та короткі плюси та мінуси.
Олексій

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