Чому для з'єднання не використовуються збіги первинного ключа / зовнішнього ключа?


48

Наскільки я міг дізнатися, що багато СУБД (наприклад, mysql, postgres, mssql) використовують комбінації fk і pk лише для обмеження змін у даних, але вони рідко використовуються в натурному режимі для автоматичного вибору стовпців для приєднання (як, наприклад, природне об'єднання з іменами). Чому так? Якщо ви вже визначили зв’язок між двома таблицями з pk / fk, чому база даних не може з'ясувати, що якщо я приєднаюся до цих таблиць, я хочу приєднати їх до стовпців pk / fk?

EDIT: щоб трохи уточнити це:

припустимо, у мене є таблиця1 і таблиця2. one1 має зовнішній ключ стовпця a, який посилається на первинний ключ у table2, стовпчик b. Тепер, якщо я приєднаюся до цих таблиць, мені доведеться зробити щось подібне:

SELECT * FROM table1
JOIN table2 ON table1.a = table2.b

Однак я вже визначив, використовуючи свої ключі, що table1.a посилається на table2.b, тому мені здається, що не повинно бути складно зробити так, щоб система СУБД автоматично використовувала table1.a та table2.b як стовпці об'єднання, такий, що можна просто використовувати:

SELECT * FROM table1
AUTO JOIN table2

Однак багато СУБД, схоже, не реалізують щось подібне.

Відповіді:


32

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

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

Дозвольте це ще раз сказати: додавши стовпці, запити, які не використовують ці стовпці, можуть перетворитись із "правильного" у "помилку"!

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

Все це було б прийнятним, якби продуктивність була підвищена. Однак це не так.

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

Тому не дивно, що більшість виробників баз даних вирішили витратити свій час на більш важливі речі.


1
Ймовірно, буде невеликий хіт продуктивності насправді, оскільки він повинен з'ясувати колонки з'єднання, а не спринцювати їх.
HLGEM

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

Додавання та зміна стовпців також може порушуватись NATURAL JOIN(саме тому я зазвичай їх уникаю), але я не думаю, що саме по собі повинно означати, що dbms не може реалізувати автоматичний спосіб приєднання таблиць на основі іноземних ключів.
Jay K

2
Багато випадків? У БД тисячі таблиць у мене є лише кілька випадків співвідношення більше ніж 1 між двома таблицями. У всякому разі, це не проблема, досить було б додати назву відношення на кшталт AUTO JOIN mytable THROUGH myrelation, було б дуже приємно.
Teejay

Це те, що ми робимо в нашому спеціально створеному .NET SQL builder, з intellisense, як-отInnerJoin(SRC_TABLE.rDEST_TABLE.REL_NAME_F01)
Teejay

27

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

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

    table: USA_States
    StateID
    StateName
    
    table: Shipment
    ShipmentID
    PickupStateID Foreign key
    DeliveryStateID Foreign key
    

    Ви можете приєднатись залежно від стану пікапа. Можливо, ви хочете приєднатися до стану доставки. Можливо, ви хочете виконати 2 приєднання для обох! Двигун sql не може знати, що ви хочете.

  2. Ви часто перетинаєте скалярні значення приєднання. Хоча скаляри зазвичай є результатом проміжних обчислень, іноді у вас буде таблиця спеціального призначення з точно 1 записом. Якби двигун спробував виявити приєднаний ключ для з'єднання .... це не мало б сенсу, оскільки перехресні з'єднання ніколи не збігаються зі стовпцем.

  3. У деяких особливих випадках ви приєднаєтесь до стовпців, де жодне не є унікальним. Тому наявність ПК / ФК у цих стовпцях неможливо.

  4. Ви можете думати , пункти 2 і 3 вище не є релевантними , оскільки ваші питання про те, коли є IS один PK / FK відносини між таблицями. Однак наявність одного таблиці PK / FK між таблицями не означає, що крім PK / FK ви не можете мати інших полів для приєднання. Двигун sql не знає, до яких полів ви хочете приєднатися.

  5. Скажімо, у вас є таблиця "USA_States" та 5 інших таблиць з FK в штати. У таблицях "п'яти" також є кілька закордонних ключів один до одного. Чи повинен двигун sql автоматично приєднуватися до "п'яти" таблиць із "USA_States"? Або він повинен приєднатися до "п'ятірки" один до одного? Обидва? Ви можете встановити відносини так, щоб двигун sql входив у нескінченний цикл, намагаючись з'єднати речі разом. У цій ситуації неможливо, тому що двигун sql здогадається, що ви хочете.

Підсумовуючи: PK / FK не має нічого спільного з приєднанням таблиці. Вони є окремими непов'язаними речами. Це просто випадковість природи, що ви часто приєднуєтесь до стовпців PK / FK.

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


7
Я вважаю зовнішні ключі та нормалізацію дуже важливими для приєднання таблиць.

3
Ваші аргументи справедливі, коли звичайне ключове слово JOIN завжди намагається відповідати цьому (як я зробив неправильно у своєму прикладі, я це виправлю). Однак багато приєднань можуть бути отримані безпосередньо лише з об'єднань, тому я не бачу жодної причини, чому не може бути явного синтаксису приєднання до них. У багатьох СУБД є природне об'єднання, що в основному робить те ж саме, але з назвами стовпців (= погано). Те ж саме можна зробити і з цим типом з'єднання, наприклад, вказавши операцію AUTO JOIN.

5
"Це просто випадковість природи, що ви часто приєднуєтесь до колон PK / FK" - я не переконаний!
день, коли

2
"Нормалізація?" Я думаю, що думка тут полягає в тому, що якби ви почали з 1NF relvar, потім розклали на 6NF relvars, великі шанси на це: a) у них будуть сторонні ключі при впровадженні, і b) вони будуть часто приєднуватися до запитів.
день, коли

4
Я б підтримав, якби не те, що "PK / FK не має нічого спільного з приєднанням таблиці".
ypercubeᵀᴹ

11

поняття "приєднаність". Відносини r1і r2є приємними, якщо і лише тоді, коли атрибути з одним іменем мають один і той же тип ... ця концепція застосовується не тільки для приєднання як такої, але і до різних інших операцій [таких як об'єднання].

SQL та реляційна теорія: як написати точний код SQL за датою CJ

Стандартний SQL вже має таку функцію, відому як NATURAL JOIN, і була реалізована в mySQL.

Хоча ваша пропозиція не настільки гідна, вона здається розумною. З сервером SQL (якому не вистачає підтримкиNATURAL JOIN ) я використовую INNER JOINпідказку SQL у програмі управління студією: коли пишуть його InteliSense, пропонуються ONпункти на основі як загальних імен атрибутів, так і зовнішніх ключів, і я вважаю це дуже корисним. Я не маю великого бажання бачити новий (стандартний) тип приєднання SQL для цього.


1
Природне з'єднання та з'єднання на загальних колонах відрізняється від & ортогонального до поняття приєднання до FK-PK. (Дивіться мою відповідь.)
philipxy

@philipxy: погодився, я не мав наміру інакше. (Ваша відповідь - відмінна відповідь!)
одного дня, коли

9

SQL прийшов першим!

Зовнішні ключі та обмеження на зовнішні ключі з’явилися пізніше і, по суті, є оптимізацією для додатків у стилі «транзакції».

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

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

Однак орган зі стандартів ANSI у всіх своїх суперечливих цілях та політиці постачальників завжди прагнув зберегти "математично доказові" властивості SQL.

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

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


3
Дякую, це мало сенс для мене! Однак, чи не мають природних приєднань однакові проблеми? Хоча природні об'єднання мають навіть більші проблеми, багато СУБД їх підтримують. Приєднання IMO на основі pk / fk було б природним приєднанням, зробленим правильно.

1
Немає різниці, що стосується більшості двигунів бази даних між природним з'єднанням та явним "ПРИЄДНАЙТЕ ... ВКЛ." Двигун аналізує запит і робить об'єднання якнайкраще на основі різних предикатів. Використання явного з'єднання не змушує використовувати певний індекс чи шлях доступу, його здебільшого підтримує синтаксис приєднання "ВЛІВО, ВНУТРІШНЬОГО, ІННЕР", який повинен знати чіткі предикати приєднання, щоб знати, коли потрібно вставити "пропущений" рядок .

6
SQL прийшов не перший! Реляційна модель (яка включала в себе поняття іноземних ключів, звичайно) була вперше окреслена EFCodd у 1969 році. SEQUEL, як і тоді, не побачив світ дня приблизно до 1974 року. Його винахідники з самого початку зрозуміли, що SEQUEL / SQL повинен був базуватися на раніше існуючій реляційній моделі - хоча SQL не вдавався бути справді реляційною мовою.
nvogel

@sqlvogel - правда! Потрібно було б фразувати це "SQL був реалізований першим".
Джеймс Андерсон

CJ Date у "Вступі до систем баз даних" (p276) говорить, що Кодд винайшов концепцію зовнішнього ключа; не говорить коли, але я припускаю, що це було до першої реалізації SQL.
день, коли

7

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

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

7

Можливо, ви працюєте за помилковим припущенням. Ви говорите «наскільки ви можете дізнатися», але не даєте жодних емпіричних чи доказових доказів. Якщо pk або fk - найкращий індекс для запиту, він буде використаний. Я не знаю, чому ви це бачите, але я гадаю, що це погано сформовані запити.


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

Деякі інструменти запитів насправді автоматично приєднуються до вас, після чого дозволяють вам видалити або відредагувати приєднання. Я думаю, що це робить MS Access's Query Builder.

Нарешті, стандарт ANSII визначає, що з'єднання повинно бути вказано. Це достатня причина, щоб не допустити цього.


3
Вибачте, можливо, я був недостатньо зрозумілий Я не кажу про індекси, я кажу про приєднання. Припустимо, у мене є table1 та table2, з fk on table1.a, який вказує на table2.b. Якщо я приєднаюся до цих таблиць, я повинен чітко сказати, що я хочу приєднати їх до стовпців a і b (наприклад, 'SELECT * FROM table1 JOIN table2 ON table1.a = table2.b '), тоді як я вже визначив у своїй базі даних схема, що ці два пов'язані. Питання в тому, чому я не можу зробити "SELECT * FROM table1 JOIN table2" і дозволити СУБД автоматично вибирати стовпці приєднання на основі fk / pk.

3
Особливо читабельність мала для мене сенс! Однак, що стандарт говорить так, це не дуже хороший аргумент ІМО. Багато стандартів раніше помилялися (наприклад, HTML).

3

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

Однак немає ніяких причин, чому інструмент дизайну запитів або текстовий редактор не може автоматично завершити приєднання за допомогою Foreign Keys так само, як вони дають вам інтелігенцію на ім'я стовпця. Ви можете редагувати запит, якщо інструмент помилився та зберегти повністю визначений запит. Такий інструмент також може корисно використовувати конвенцію про іменування стовпців «Іноземні ключі» іменем таблиці «батьків» та стовпцями з тим самим іменем у батьківській / дочірній таблиці тощо.

(Моя дружина досі не може зрозуміти різницю між Management Studio і Sql Server і говорить про запуск сервера sql, коли вона запускає студію управління!)


3

Природне з'єднання "автоматично" приєднується до рівності загальних стовпців, але ви повинні лише писати, що якщо це ви хочете, виходячи із значень таблиці та бажаного результату. Немає "автоматично" знати, як дві таблиці "повинні" бути об'єднані або будь-яким іншим чином будь-яка таблиця "повинна" з'являтися в запиті. Нам не потрібно знати обмежень для запиту. Їх наявність просто означає, що вхід може бути обмеженим, і, отже, вихід може бути занадто. Ви можете визначити якийсь оператор join_on_fk_to_pk, який "автоматично" приєднується до оголошених обмежень; але якщо ви хочете, щоб значення запиту залишалося таким же, якщо змінюються лише обмеження, але не значення таблиці, тоді вам доведеться змінити цей запит, щоб не використовувати нові оголошені компоненти.вже залишає значення однаковим, незважаючи на будь-які зміни обмежень .

Які обмеження мають місце (включаючи ПК, FK, UNIQUE & CHECK), не впливають на те, що означають таблиці. Звичайно, якщо значення таблиці змінюються, то протипоказання можуть змінюватися. Але якщо обмеження змінюються, це не означає, що запити повинні змінюватися.

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

Чи є якесь правило для побудови SQL-запиту з людського читаного опису?


2

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

Як зазначали інші, деякі реалізації використовують розширення, де join (column) об'єднує дві таблиці на основі загального імені стовпця, який дещо схожий. Але він не широко поширений. Зауважте, що це розширення відрізняється від SELECT * FROM employee NATURAL JOIN department;синтаксису, який не включає спосіб вказувати, які стовпці використовувати. Не покладайтеся на зв’язок між таблицями, що робить їх ненадійними (природний синтаксис приєднання більше, ніж розширення).

Немає принципової перешкоди для "внутрішньої таблиці приєднання до PKFK", де PKFK - це ключове слово, що означає "зв'язок зовнішнього ключа, визначений між двома таблицями", можуть бути проблеми з декількома fk до однієї таблиці, але це може просто спричинити помилку. Питання полягає в тому, чи вважають люди, які розробляють мову, що: а) гарна ідея та б) краще працювати над тим, як змінюються інші мови ...


3
Це передбачає, що це гарна ідея, що вони вже повинні були зробити. Цілком ймовірно, що вони вже це розглянули і вирішили цього не робити. Можливо, це дуже погана ідея на практиці: Шьорд згадав приклад, коли запит може бути порушений лише через додавання нового стовпця та співвідношення ФК. Лорд Тидус також пояснює, що зовнішні ключі несуть відповідальність від диктування способів з'єднання ваших таблиць.

1
@JonathanHobbs: Я мав на увазі, що моя відповідь є як правило нейтральною. Але відмовляємось від нейтралітету. Логіка Шеерда є хибною. Зміни до таблиць вже розбивають запити, додаючи новий стовпчик до таблиць. Первинний ключ буде або розбивати запити, або починати повертати неправильні результати. Це насправді би ізолювало вас від такої міри, доки зберігалися відносини таблиці, зміни стовпців можна було б зробити безпечно. Це, ймовірно, збільшить використання відносин FK, оскільки це було б корисно для чогось іншого, ніж RI. Більшість приєднується знаходяться на ПК або включають Pk.To для обробки кількох fk, використовуйте ім'я стовпця.
jmoreno

1

Якщо упущення пункту ON передбачається, що слід слідувати полям, заснованим на референтній цілісності, як би ви зробили декартовий продукт?

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

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


@JeffO: Основна перевага полягає в тому, що він висловлює наміри точніше, дуже чітко, декларативно. Приєднання до назв стовпців нічого не означають, крім того, що частина вмісту стовпців схожа на вміст у іншому (але може бути не того самого типу). Приєднання до fk ref, говорить про те, що є fk ref, жоден список стовпців не означатиме, що між таблицями був лише 1 fk, або, навпаки, є 1+ (врахуйте клавішу багатокольону з більш ніж 1 ref, що відбувається, коли ви змішуєте стовпці c1 = fk1_c1 і c2 = fk2_c2). Навіть із більшою кількістю друку в середньому, це було б добре.
jmoreno

Використання (INNER) ПРИЄДНУЙТЕСЯ без увімкнення - це не стандартний SQL. Кома, КРЕШЕ ПРИЄДНАЙТЕСЬ & (ВНУТРІШНЯ або будь-яка зовнішня) ПРИЄДНАЙТЕСЬ НА 0 = 0 повернення декартового товару.
філіпсі

-1

Чому база даних не може зрозуміти, що якщо я приєднуюся до цих таблиць, я хочу приєднатись до них у стовпцях pk / fk?

Частками причини є:

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

2 - Існують різні типи з'єднань (ліві, праві, внутрішні) - Внутрішні приєднання - лише 1 з них.

3 - Стандарт SQL може керуватися принципом бути мовою нижчого рівня, що дозволяє діалектам вищого рівня формувати інтелект, використовуючи його. Порівняння дещо чіткіше, якщо ви думаєте про мову 4-го покоління порівняно з мовою 3-го покоління. Насправді один інструмент, який я використав, IEF, дозволив вам написати щось подібне:

ReadEach Customer 
Where Customer Places Orders and That Customer LivesIn "California" 
and OrderValue > 100.00

Підсумовуючи це, ваша пропозиція є цікавою і може бути реалізована як частина стандартної, так і як збережена процедура (за замовчуванням це буде Внутрішнє з'єднання).


-10

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

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

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

Скажу прямо: не використовуйте цю функцію SQL Foreign Keyвзагалі , доки не потрапите на якусь велику систему з проблемами з продуктивністю. Явний повідомляє , яке поле є зовнішнім ключем , і який не є тільки використовуватися для індексації, і вона невидима для користувача БД.

Це вводить в оману?
Так.

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

Повністю ігноруючи іноземні ключі до необхідності ... виправлений SQL для мене?
Так!

І чому чорт все це сталося в першу чергу?
Ну а функція, яку ми називаємо сторонніми ключами, була додана пізніше до SQL; SQL - це стандарт, який розвивався з часом знизу вгору. Продавці реалізували смішні функції, тоді як стандартні органи стикалися з обличчям.

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


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

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