Чи слід додати перехідні зовнішні ключі?


11

Простий приклад: є таблиця клієнтів.

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

Усі інші дані в базі даних повинні посилатись на а Customer, наприклад, Ordersвиглядає так:

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

Припустимо, зараз існує таблиця, що посилається на Orders:

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

Чи слід додати окремий зовнішній ключ від Itemsдо Customers?

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

Замість цього зображення: чи слід додати пунктирну лінію / FK?

Проста схема прикладу


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


2
Ні, ви не повинні. Немає необхідності в додатковому ФК. Обмеження застосовуються за допомогою двох інших ФК.
ypercubeᵀᴹ

@ypercube Чи є штрафи за ефективність роботи за надмірний FK? Будь-які переваги, про які ви могли подумати? ...
vektor

1
@vektor, аспекти продуктивності, ймовірно, змінюються від одного rdbms до іншого, але, як правило, ви отримуєте вплив на продуктивність для кожного нового FK, який ви додаєте, тому що кожне вставлення / оновлення / видалення в одній із таблиць PK / FK має бути перевірено на обмеження. За великих таблиць ПК ця покарання за продуктивність може бути досить суворим.
Даніель Хатмахер

Відповіді:


6

Я думаю, що це оригінальна ідея.

введіть тут опис зображення

Перше, що слід помітити, це те, що ПК у таблиці LineItem має три атрибути {CustomerID, CustomerOrderNo, OdrerItemNo}, на відміну від двох у вашому прикладі.

Друге, що слід зазначити, - плутанина, що виникає внаслідок використання загального idімені для атрибута.

В CustomerOrderNoідеалі вони повинні бути (1,2,3 ..) для кожного клієнта та OrderItemNo(1,2,3 ...) для кожного замовлення.

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

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

що часто не є переважним у середовищах з великим обсягом транзакцій, тому звичайно бачити, що вони замінені автоматичним збільшенням, по суті служать одній і тій же цілі. Це правда, що цей автоматичний приріст тепер унікальний, тому він може використовуватися як КЛЮЧОВИЙ - але ви можете вирішити, щоб на нього розглядати як на необхідний компроміс для OrderItemNo.

Отже, з деяким перейменуванням CustomerOrderNo -> OrderNoта OrderItemNo-> ItemNoви можете прийти до цієї моделі

введіть тут опис зображення

Отже, якщо ви подивитесь на Orderнаступне, це унікальне

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

Зауважте, що {CustomerID, OrderNo}він розповсюджується LineItemна службу як ФК.

Якщо ви трохи примружили, це близько до вашого прикладу, але PKs {ItemNo} and {OrderNo}лише - на відміну від двох ПК у стовпці з вашого прикладу.

Тепер питання полягає в тому, чому б не спростити щось подібне?

введіть тут опис зображення

Що добре, але вводить PATH ЗАЛЕЖНІСТЬ - ви не можете приєднатися LineItemдо Customerбезпосередньо, повинні використовувати Orderв поєднанні.


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


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

2

"Елемент" не повинен посилатися на "замовника" безпосередньо, оскільки це має на увазі "замовлення" товару. Отже, стовпці "клієнт" у таблиці "позиції" вам взагалі не знадобляться.

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

Якщо order.id - стовпець ідентичності, розгляньте питання про видалення items.customer.


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

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

Гаразд, я оновив свою відповідь. :)
Даніель Хатмахер

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

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