Kiedy powinienem używać relacji jeden do jednego?

92

Przepraszam za to pytanie noob, ale czy istnieje realna potrzeba używania relacji jeden do jednego z tabelami w Twojej bazie danych? Możesz zaimplementować wszystkie niezbędne pola w jednej tabeli. Nawet jeśli dane stają się bardzo duże, możesz wyliczyć nazwy kolumn, których potrzebujesz w SELECTinstrukcji, zamiast używać SELECT *. Kiedy naprawdę potrzebujesz tej separacji?

Pavel Shchegolevatykh
źródło

Odpowiedzi:

105

1 do 0..1

  • „1 do 0..1” między super a podklasami jest używany jako część strategii „wszystkie klasy w oddzielnych tabelach” do implementacji dziedziczenia .

  • „1 do 0..1” można przedstawić w pojedynczej tabeli z częścią „0..1” objętą polami dopuszczalnymi do wartości NULL. Jeśli jednak relacja to głównie „1 do 0” i tylko kilka wierszy „1 do 1”, podzielenie części „0..1” na osobną tabelę może zaoszczędzić pewne korzyści związane z pamięcią masową (i wydajnością pamięci podręcznej). Niektóre bazy danych są bardziej oszczędne w przechowywaniu wartości NULL niż inne, więc „punkt odcięcia”, w którym ta strategia staje się opłacalna, może się znacznie różnić.

1 do 1

  • Prawdziwe „1 do 1” dzieli dane w pionie, co może mieć wpływ na buforowanie. Bazy danych zazwyczaj implementują pamięci podręczne na poziomie strony, a nie na poziomie poszczególnych pól, więc nawet jeśli wybierzesz tylko kilka pól z wiersza, zwykle cała strona, do której należy wiersz, zostanie zapisana w pamięci podręcznej. Jeśli wiersz jest bardzo szeroki, a wybrane pola stosunkowo wąskie, w końcu zbuforujesz wiele informacji, których w rzeczywistości nie potrzebujesz. W takiej sytuacji przydatne może być podzielenie danych w pionie, tak aby tylko węższa, częściej używana część lub wiersze były zapisywane w pamięci podręcznej, dzięki czemu więcej z nich może zmieścić się w pamięci podręcznej, dzięki czemu pamięć podręczna jest efektywnie „większa”.

  • Innym zastosowaniem partycjonowania pionowego jest zmiana zachowania blokowania: bazy danych zazwyczaj nie mogą blokować się na poziomie pojedynczych pól, tylko całych wierszy. Dzieląc wiersz, pozwalasz na blokadę tylko na jednej z jego połówek.

  • Wyzwalacze są również zwykle specyficzne dla tabeli. Chociaż teoretycznie można mieć tylko jedną tabelę i wyzwalacz ignoruje „niewłaściwą połowę” wiersza, niektóre bazy danych mogą nakładać dodatkowe ograniczenia na to, co wyzwalacz może, a czego nie może zrobić, co może uczynić to niepraktycznym. Na przykład Oracle nie pozwala modyfikować tabeli mutacji - mając oddzielne tabele, tylko jedna z nich może mutować, więc nadal możesz modyfikować drugą z wyzwalacza.

  • Osobne tabele mogą zapewnić bardziej szczegółowe zabezpieczenia.

Te uwagi są w większości przypadków nieistotne, dlatego w większości przypadków należy rozważyć scalenie tabel „1 do 1” w jedną tabelę.

Branko Dimitrijevic
źródło
20

Jeśli dane w jednej tabeli są powiązane, ale nie „należą” do jednostki opisanej przez drugą, to jest to kandydat do zachowania ich oddzielnie.

Może to przynieść korzyści w przyszłości, jeśli oddzielne dane będą musiały być powiązane również z jakimś innym podmiotem.

Sepster
źródło
19

Jeśli umieścisz dwie tabele jeden do jednego w jednej, prawdopodobnie wystąpią problemy z semantyką. Na przykład, jeśli każde urządzenie ma jednego pilota, umieszczenie urządzenia i pilota wraz z ich cechami w jednej tabeli nie brzmi całkiem dobrze. Być może trzeba będzie nawet poświęcić czas na ustalenie, czy określony atrybut należy do urządzenia, czy do pilota zdalnego sterowania.

Może się zdarzyć, że połowa Twoich kolumn pozostanie pusta przez długi czas lub nigdy nie zostanie wypełniona. Na przykład samochód może mieć jedną przyczepę z wieloma cechami lub może jej nie mieć. Będziesz więc mieć wiele nieużywanych atrybutów.

Jeśli Twoja tabela ma 20 atrybutów, a tylko 4 z nich są używane sporadycznie, warto podzielić tabelę na 2 tabele ze względu na problemy z wydajnością.

W takich przypadkach nie warto mieć wszystkiego w jednej tabeli. Poza tym nie jest łatwo poradzić sobie z tabelą, która ma 45 kolumn!

superM
źródło
17

Moje 2 centy.

Pracuję w miejscu, w którym wszyscy rozwijamy się w dużej aplikacji, a wszystko jest modułem. Na przykład mamy userstabelę i mamy moduł, który dodaje dane z Facebooka dla użytkownika, kolejny moduł, który dodaje dane z Twittera do użytkownika. Moglibyśmy zdecydować o odłączeniu jednego z tych modułów i usunięciu całej jego funkcjonalności z naszej aplikacji. W tym przypadku każdy moduł dodaje własną tabelę z relacjami 1: 1 do userstabeli globalnej , na przykład:

create table users ( id int primary key, ...);
create table users_fbdata ( id int primary key, ..., constraint users foreighn key ...)
create table users_twdata ( id int primary key, ..., constraint users foreighn key ...)
santiago arizti
źródło
13

Najrozsądniej byłoby to wykorzystać, gdyby istniały dwie odrębne koncepcje, które zawsze odnosiłyby się tylko w ten sposób. Na przykład, samochód może mieć tylko jednego aktualnego Kierowcę, a Kierowca może prowadzić tylko jeden samochód na raz - więc związek między koncepcjami Samochód i Kierowca będzie wynosił 1 do 1. Akceptuję, że jest to wymyślony przykład pokazujący punkt.

Innym powodem jest to, że chcesz specjalizować koncepcję na różne sposoby. Jeśli masz tabelę Person i chcesz dodać koncepcję różnych typów osób, takich jak Pracownik, Klient, Akcjonariusz - każda z nich będzie potrzebować innego zestawu danych. Dane, które są między nimi podobne, znajdowałyby się w tabeli Osoba, informacje specjalistyczne znajdowałyby się w tabelach dla Klienta, Akcjonariusza, Pracownika.

Niektóre silniki baz danych mają problemy z wydajnym dodawaniem nowej kolumny do bardzo dużej tabeli (wielu wierszy) i widziałem, jak tabele rozszerzeń zawierają nową kolumnę, a nie nową kolumnę dodawaną do oryginalnej tabeli. Jest to jedno z bardziej podejrzanych zastosowań dodatkowych tabel.

Możesz również zdecydować o podzieleniu danych dla jednej koncepcji między dwie różne tabele ze względu na problemy z wydajnością lub czytelnością, ale jest to dość szczególny przypadek, jeśli zaczynasz od zera - te problemy pojawią się później.

Fenton
źródło
5

niezbyt często.

możesz znaleźć pewne korzyści, jeśli musisz zaimplementować pewne zabezpieczenia - aby niektórzy użytkownicy widzieli niektóre kolumny (tabela1), a inne nie (tabela2).

Oczywiście niektóre bazy danych (Oracle) pozwalają na wykonanie tego rodzaju zabezpieczenia w tej samej tabeli, ale inne nie.

Krzykliwy
źródło
5

Masz na myśli normalizację bazy danych. Przykładem, który przychodzi mi do głowy w aplikacji, którą prowadzę, są Items. Aplikacja pozwala użytkownikowi na sprzedaż wielu różnych typów przedmiotów (np. InventoryItems, NonInventoryItems, ServiceItems itp.). Chociaż mógłbym przechowywać wszystkie pola wymagane przez każdy przedmiot w jednej tabeli pozycji, znacznie łatwiej jest mieć podstawową tabelę pozycji, która zawiera pola wspólne dla wszystkich pozycji, a następnie oddzielne tabele dla każdego typu pozycji (tj. etc ..), które zawierają pola specyficzne tylko dla tego typu elementu. Wtedy tabela pozycji będzie miała klucz obcy do określonego typu elementu, który reprezentuje. Relacja między określonymi tabelami pozycji a podstawową tabelą pozycji byłaby jeden do jednego.

Poniżej znajduje się artykuł dotyczący normalizacji.

http://support.microsoft.com/kb/283878

Konik polny
źródło
3

Jak w przypadku wszystkich pytań projektowych, odpowiedź brzmi „to zależy”.

Jest kilka uwag:

  • jak duża będzie tabela (zarówno pod względem pól, jak i wierszy)? Przechowywanie nazwy użytkownika i hasła z innymi, rzadziej używanymi danymi może być niewygodne zarówno z punktu widzenia konserwacji, jak i programowania

  • pola w połączonej tabeli, które mają ograniczenia, mogą z czasem stać się niewygodne w zarządzaniu. na przykład, jeśli wyzwalacz musi zostać uruchomiony dla określonego pola, stanie się to przy każdej aktualizacji tabeli, niezależnie od tego, czy dotyczy to pola.

  • na ile jesteś pewien, że związek będzie 1: 1? Jak wskazuje to pytanie, sprawy mogą szybko się skomplikować.

Rob Allen
źródło
3

Innym przypadkiem użycia może być: możesz importować dane z jakiegoś źródła i codziennie je aktualizować, np. Informacje o książkach. Następnie samodzielnie dodajesz dane o niektórych książkach. Wtedy sensowne jest umieszczenie zaimportowanych danych w innej tabeli niż własne dane.

Sztylet
źródło
2

W praktyce zwykle spotykam dwa ogólne rodzaje relacji 1: 1:

  1. Relacje IS-A, znane również jako relacje nadtyp / podtyp. Dzieje się tak, gdy jeden rodzaj podmiotu jest w rzeczywistości typem innego podmiotu (EntityA IS A EntityB). Przykłady:

    • Osoba fizyczna, z osobnymi podmiotami dla Księgowego, Inżyniera, Sprzedawcy w tej samej firmie.
    • Element pozycji z oddzielnymi encjami dla Widget, RawMaterial, FinishedGood itp.
    • Jednostka samochodu z osobnymi jednostkami dla ciężarówki, sedana itp.

    We wszystkich tych sytuacjach encja nadtypu (np. Osoba, Przedmiot lub Samochód) miałaby atrybuty wspólne dla wszystkich podtypów, a byty podtypów miałyby atrybuty unikalne dla każdego podtypu. Klucz podstawowy podtypu byłby taki sam jak klucz nadtypu.

  2. Relacje „szefa”. Dzieje się tak, gdy osoba jest jedynym szefem, kierownikiem lub przełożonym jednostki organizacyjnej (działu, firmy itp.). Gdy w jednostce organizacyjnej dozwolony jest tylko jeden szef, wówczas istnieje relacja 1: 1 między osobą, która reprezentuje szefa, a jednostką jednostki organizacyjnej.

Tripartio
źródło
1
Drugi przykład mi się podoba. Możesz mieć jednostkę „Dział” i jednostkę „Pracownik”. W jednym dziale masz wielu pracowników, a pracownik może pracować tylko w jednym dziale. To jest 1: n. Pracownik może być przełożonym działu - tylko jednego działu, a dział ma tylko jednego przełożonego. W rezultacie otrzymujesz dwie tabele połączone dwoma relacjami - 1: ni 1: 1.
cezar
2

Po pierwsze, myślę, że jest to kwestia modelowania i definiowania, co składa się na odrębną całość. Załóżmy, że masz customersjednego i tylko jednego singla address. Oczywiście możesz zaimplementować wszystko w jednej tabeli customer, ale jeśli w przyszłości pozwolisz mu mieć 2 lub więcej adresów, będziesz musiał to zmienić (nie jest to problem, ale podjąć świadomą decyzję).

Przychodzi mi też do głowy ciekawy przypadek, o którym nie wspomniano w innych odpowiedziach, w którym podział tabeli może być przydatny:

Wyobraź sobie, znowu, że masz customerspo jednym address, ale tym razem posiadanie adresu jest opcjonalne. Oczywiście można to zaimplementować jako NULLzbiór kolumn, takich jak ZIP,state,street. Ale załóżmy, że biorąc pod uwagę, że masz adres państwo nie jest obowiązkowe, ale ZIP. Jak to wymodelować w jednej tabeli? Mógłbyś użyć ograniczenia na customertabeli, ale znacznie łatwiej jest podzielić w innej tabeli i nadać parametr Foreign_key wartość NULL. W ten sposób twój model jest znacznie bardziej wyraźny, mówiąc, że jednostka address jest opcjonalna i że ZIPjest opcjonalnym atrybutem tej jednostki.

polvoazul
źródło
0

W moim czasie programowania spotkałem się z tym tylko w jednej sytuacji. Dzieje się tak, gdy istnieje relacja 1 do wielu i 1 do 1 między tymi samymi 2 podmiotami („Jednostka A” i „Jednostka B”).

Gdy „Podmiot A” ma wiele „Podmiotów B”, a „Podmiot B” ma tylko 1 „Podmiot A”, a „Podmiot A” ma tylko 1 aktualny „Podmiot B”, a „Podmiot B” ma tylko 1 „Podmiot A”.

Na przykład samochód może mieć tylko jednego aktualnego kierowcę, a kierowca może prowadzić tylko jeden samochód na raz - więc związek między koncepcjami samochodu i kierowcy wynosiłby 1 do 1. - Ten przykład zaczerpnąłem z odpowiedzi @Steve Fenton

Gdzie kierowca może prowadzić wiele samochodów, ale nie w tym samym czasie. Zatem encje Samochód i Kierowca to 1-do-wielu lub wiele-do-wielu. Ale jeśli musimy wiedzieć, kto jest obecnym sterownikiem, potrzebujemy również relacji 1 do 1.

Jo Smo
źródło
0

Innym przypadkiem użycia może być przekroczenie maksymalnej liczby kolumn w tabeli bazy danych. Następnie możesz dołączyć do innego stołu za pomocą OneToOne

db303
źródło