Чи потрібний стовпчик унікального ідентифікатора в таблиці багато-до-багатьох (з'єднання)?


22

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

Тепер таблиці програм та дозволів прості:

Applications
--------------
PK  ApplicationID
    Name

Permissions
--------------
PK  PermissionID
    Name

Але який найкращий спосіб зробити таблицю приєднання? У мене є два варіанти:

ApplicationPermissions
-----------------------
PK  ApplicationPermissionID
CU  ApplicationID
CU  PermissionID

АБО

ApplicationPermissions
-----------------------
CPK ApplicationID
CPK PermissionID

PK = Primary Key
CPK = Composite Primary Key
CU = Composite Unique Index

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

Відповіді:


20

Я вважаю, ви маєте на увазі таблицю "з'єднання", а не таблицю "приєднання".

Немає необхідності в таблиці переходу, щоб було власне поле ідентифікації. Вам ніколи не потрібно буде приєднуватися або фільтрувати такий ідентифікатор. Ви б приєдналися або фільтрували лише ідентифікаційні таблиці таблиць, які ви картаєте. Ідентифікатор на перехідній таблиці - це витрата дискового простору.

Тому "найкращим" варіантом є уникнення посвідчення особи. Зазвичай таблиця з'єднання матиме 2 індекси, що охоплюють. Кожен індекс покриття, використовуючи один із відображених ідентифікаторів як основне поле сортування.

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

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


2
Ну, ви вже заявляли, що додавання ідентифікатора - це незначна поступка, яку легко подолати потенційними вигодами, тому мені здається, що (враховуючи, що наявність унікальної ідентифікатора в кожній таблиці - це більш-менш найкраща практика в більшості СУБД та ОРМ) ви б прихильнили наявність ідентифікатора як "найкращого" чи "типового" варіанту, а не такого.
Роберт Харві

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

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

1
"витрата дискового простору." - Я думаю, що деякі двигуни (InnoDB?) Так чи інакше створюють (внутрішній) первинний ключ, якщо ви не зробите його самостійно - так що ви, власне, не можете отримати дисковий простір, не маючи його.
Олексій

@Alex. Ви ставите складений ПК на відображені ідентифікатори.
mike30

11

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

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

Інша справа, коли ви почнете з комбінованих ПК, ви, ймовірно, через кілька разів зіткнетеся з потребою у комбінованих зовнішніх ключах (оскільки ви можете прийти до моменту, коли ви хочете додати FK ApplicationPermissionsтаблицю до своєї таблиці). Тоді наступною вимогою може бути, щоб цей ФК був унікальним у поєднанні з іншими атрибутами або зовнішніми ключами - що призведе до загальної складності в цілому. Звичайно, нічого, що неможливо впоратися з більшістю сучасних систем БД, але рівномірне рішення полегшує життя програмістів набагато простіше.

І нарешті, таке твердження SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)добре працює з одним стовпчиком як основним ключем, але я досі не бачив діалекту SQL, який дозволяє це робити за допомогою комбінованих ключів. Якщо ви заздалегідь знаєте, що вам ніколи не знадобиться такий запит, добре, але не дивуйтеся, якщо завтра ви отримаєте вимогу, яку найпростіше вирішити за допомогою такого типу SQL.

Звичайно, коли ви очікуєте, що ваш ApplicationPermissionsстіл може містити кілька сотень мільйонів рядків, тоді вам слід подумати, щоб уникнути чогось подібного ApplicationPermissionsID.


Хоча я не закінчив обрати вашу відповідь. Мені подобаються його аспекти. Дякуємо за ваші думки (резюме).
солідау

6

Хоча відповідь Майка хороша, ось чому я додав би окреме поле для посвідчення чи ні.

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

  2. Подумайте про використання окремого поля ідентифікатора, якщо API або будь-яка існуюча логіка, як правило, використовують окремі поля для отримання / редагування об'єктів. Це може допомогти іншим людям слідувати вашому коду в контексті більшого проекту.

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


-5
table Person
   Id int identity(1,1) not null primary key
   ...other fields go here...
table Address
   Id int identity(1,1) not null primary key
   ...other fields go here...
table PersonAddress
   Id int identity(1,1) not null primary key
   PersonId int not null
   AddressId int not null

Не забудьте створити індекс і зовнішній ключ на обох PersonIdі AddressId.

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


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