SQL - первинний ключ таблиці багато-до-багатьох


125

Це запитання виникає після прочитання коментаря до цього питання:

Дизайн баз даних

Створюючи таблицю "багато на багато", чи слід створити складений первинний ключ на двох стовпцях із зовнішнім ключем або створити первинний ключ автоматичного збільшення сурогатного "ідентифікатора" та просто поставити індекси на дві колонки FK (а може бути унікальне обмеження)? Які наслідки для продуктивності для вставлення нових записів / повторної індексації у кожному випадку?

В основному це:

PartDevice
----------
PartID (PK/FK)
DeviceID (PK/FK)

порівняно з цим:

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)

Коментолог каже:

виготовлення двох ідентифікаторів PK означає, що таблиця фізично сортується на диску в такому порядку. Отже, якщо ми вставимо (Part1 / Device1), (Part1 / Device2), (Part2 / Device3), то (Частина 1 / Device3) база даних повинна буде розбити таблицю на частини та вставити останню між записами 2 та 3. Для багато записів, це стає дуже проблематичним, оскільки воно включає переташування сотень, тисяч чи мільйонів записів кожного разу, коли додається один. На відміну від цього, автоматичне збільшення ПК дозволяє нові записи записувати до кінця.

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


Ось Силимар питання відповідав на SO: stackoverflow.com/questions/344068 / ...
Тоні

(Спробував додати це до мого попереднього коментаря, але не можу) Залежно від кількості вставок ви також можете періодично перебудовувати свій індекс, щоб забезпечити швидке повернення результатів. У SQL Server ви також можете налаштувати FILLFACTOR індексу, щоб забезпечити достатньо місця для вставок, перш ніж він повинен переміщувати дані.
Тоні

1
Чи не відповідь на це залежить від того, яка СУБД використовується? Я підозрюю, що MySQL буде вести себе по-справжньому в цьому випадку, SQL-сервер трохи по-іншому і т. Д.
Radu Murzea

Caveat: Без конкретного тегу бази даних, багато з того, що тут сказано, є підозрілим. Різні двигуни працюють по-різному!
Рік Джеймс

Відповіді:


85

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

Вам не знадобляться індекси для окремих стовпців, оскільки таблицю слід використовувати лише коли-небудь разом для об'єднання двох посиланих таблиць.

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

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

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


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

5
@buffer, я буду стояти за цей коментар (технічно це узагальнення, тільки якщо я скажу "всі таблиці", "переважна більшість" ґрунтується на досвіді). Давайте також подумаємо про ваш приклад, замовлення створюється один раз (воно може періодично оновлюватися, але це навряд чи змінить інформацію про ключ / індекс, більше, щоб вплинути на такі речі, як статус замовлення. Однак ці оновлення та вибір, який вам потрібно буде зробити роздруковувати рахунки-фактури або генерувати звіти про управління збираються переважати над оригінальною вставкою.
paxdiablo

Подумайте, Amazon - тисячі замовлень, створених щогодини.
користувач

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

1
Моя думка, чи insertбуде важливо, чи буде це робити тисячі разів на годину. Ви не можете просто проігнорувати це лише тому, що співвідношення insertдо selectстановить <1. У цьому випадку замовник дбає про те, скільки часу потрібно для оформлення замовлення.
користувач

19

Для таблиць посилань не потрібен сурогатний ключ.

Один ПК на (col1, col2) та інший унікальний індекс на (col2, col1) - це все, що вам потрібно

Якщо ви не використовуєте ORM, який не справляється і не диктує ваш дизайн БД для вас ...

Редагувати: Я відповів те саме тут: SQL: Вам потрібен автоматичний додатковий первинний ключ для таблиць «Багато-багато»?


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

@gbn: Другий індекс на (col2, col1) не повинен бути унікальним, правда?
користувач

1
ставити унікальний індекс на (col1, col2) після того, як він вже є ПК - це зайве
Дон Чедл

@mmcrae: де ми це робимо?
gbn

2
@mmcrae: Ваш коментар - "додавання унікального індексу на (col1, col2) ..". Порядок стовпців в індексі має значення. (col2, col1)не є (col1, col2). ПК (col1, col2)може бути не підходящим для всіх запитів і генерувати сканування, тому наявність зворотного боку покращує ефективність, оскільки дозволяє шукати, де кращий col2. Наприклад, перевірка FK, коли таблиця з col2 має видалення. Дитячий стіл за
розмірами

12

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

наприклад

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)
Other Details

Легко витягнути "Інші деталі", використовуючи PartDevice.ID як FK. Таким чином, необхідне використання додаткового первинного ключа.


1
Дякую! Я прийшов до відповіді, коли шукав майже той самий сценарій, який ви описали. Але ви відійшли від свого першого речення, додавши "Інші деталі". Що робити, якщо у мене було багато-багато таблиць відображення, на які мені потрібно посилатися з іншої таблиці? Це означає, що таблиця зі множиною до багатьох не зберігає жодної іншої інформації ... Чи має сенс додатковий стовпець ідентифікатора? Якщо ні, то як посилатися на один запис таблиці відображення?
мізантроп

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

6

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


2

Тож здається, що якби ТІЛЬКО завданням було з'єднати дві таблиці, найкращим ПК був би ПК з двома стовпцями.

Але якщо він служить іншим цілям, тоді додайте інший NDX як ПК із зовнішніми ключами та другим унікальним індексом.

Індекс або ПК - найкращий спосіб переконатися у відсутності дублікатів. ПК дозволяє таким інструментам, як Microsoft Management Studio, виконувати певну роботу (створюючи представлення даних) для вас

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