tabele z odnośnikami, dobre czy złe? [Zamknięte]


37

Reprezentujący położenia geograficzne w aplikacji projekt bazowego modelu danych sugeruje dwie wyraźne opcje (a może więcej?).

Jedna tabela z samodzielnie odwołującą się kolumną parent_id uk - londyn (london parent id = identyfikator UK)

lub dwie tabele, z relacją jeden do wielu przy użyciu klucza obcego.

Preferuję jedną tabelę samo-odwołującą się, ponieważ pozwala łatwo rozszerzyć się na tyle podregionów, ile potrzeba.

Zasadniczo, czy ludzie odwracają się od tabel odwołujących się do siebie, czy też są OK?

Odpowiedzi:


40

Nic złego w tabelach z odnośnikami.

Jest to wspólny wzorzec projektowania bazy danych dla głęboko zagnieżdżonych hierarchii.


@NimChimpsky - Podobnie jak koncepcja rekurencji, ten pomysł jest dla niektórych trudny.
Oded

2
(Przynajmniej) Oracle ma nawet specjalną konstrukcję SQL, klauzulę „START WITH - CONNECT BY”, aby radzić sobie z tabelami z odnośnikami.
user281377,

1
@ user281377 - I SQL Server wprowadził ten hierarchyidtyp.
Oded

zapisz hibernację, aby miał swój własny specjalny sos
NimChimpsky

4
@NimChimpsky - Rozważ spojrzenie na „Model zestawu zagnieżdżonego” jako alternatywę dla tej kolumny „rodzic_id” - zapewnia on tę samą funkcjonalność, ale lepszą wydajność i łatwiejsze zapytania w celu wyodrębnienia hierarchii. en.wikipedia.org/wiki/Nested_set_model Seria książek Joe Celko „SQL For Smarties” zawiera kilka świetnych przykładowych instrukcji SQL dotyczących zestawów zagnieżdżonych.
Keith Palmer Jr.

7

Nekromancja.
Prawidłowa odpowiedź to: zależy od silnika bazy danych i narzędzia zarządzania.

Zróbmy przykład:
mamy tabelę raportów,
a raport może mieć element nadrzędny (punkt menu, podobny do kategorii),
a ten element nadrzędny może mieć element nadrzędny (np. Centrum zysków)
i tak dalej w nieskończoność.

Najprostszy przykład standardowej relacji rekurencyjnej, tak jak w przypadku każdej jednostki / hierarchii odwołującej się do siebie.

Wynikowa tabela SQL-Server to:

IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports 
GO



CREATE TABLE dbo.T_FMS_Reports 
( 
     RE_UID uniqueidentifier NOT NULL 
    ,RE_RE_UID uniqueidentifier NULL 
    ,RE_Text nvarchar(255) NULL 
    ,RE_Link nvarchar(400) NULL 
    ,RE_Sort int NOT NULL 
    ,RE_Status int NOT NULL 
    ,PRIMARY KEY CLUSTERED ( RE_UID ) 
); 

GO

ALTER TABLE dbo.T_FMS_Reports  WITH CHECK ADD  CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID) 
REFERENCES dbo.T_FMS_Reports (RE_UID) 
-- ON DELETE CASCADE -- here, MS-SQL has a problem 
GO

ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports 
GO

Ale pojawia się problem:
gdy trzeba usunąć menupunkt ze wszystkimi jego podmenu, NIE MOŻESZ ustawić kaskady usuwania, ponieważ Microsoft SQL Server nie obsługuje rekurencyjnych kasowanych kasowań (z drugiej strony PostGreSQL nie robi tego (ale tylko jeśli graph nie jest cykliczny], podczas gdy MySQL w ogóle nie lubi tego rodzaju struktury tabel, ponieważ nie obsługuje rekurencyjnych CTE).

W ten sposób wysadzasz z nim integralność usuwania / funkcjonalność, co powoduje, że obowiązkowe jest wdrożenie takiej funkcjonalności we własnym kodzie lub w procedurze przechowywanej (jeśli RDBMS obsługuje procedury przechowywane).

To bez wątpienia wysadzi jakikolwiek w pełni automatyczny import / eksport danych dynamicznych, ponieważ nie można po prostu uruchomić instrukcji usuwania dla wszystkich tabel zgodnie z relacjami klucza obcego (nie odwołując się do siebie), ani nie można wykonać prostego wyboru * i utwórz wstawkę dla każdego wiersza w dowolnej kolejności.

Na przykład, gdy tworzysz skrypt INSERT za pomocą SSMS, wówczas SSMS nie otrzyma klucza obcego, a zatem faktycznie tworzy instrukcje insert, które wstawią wpisy z zależnościami, zanim wstawią element nadrzędny zależności, co zakończy się błędem , ponieważ klucz obcy jest na swoim miejscu.

Jednak przy odpowiednich systemach zarządzania bazami danych (takich jak PostgreSQL), z odpowiednim oprzyrządowaniem, nie powinno to stanowić problemu. Po prostu rozumiem, że tylko dlatego, że płacisz dużo za RDBMS (patrzę na ciebie, Microsoft; Oracle =?) I / lub jego pasek narzędzi, nie oznacza to, że jest odpowiednio zaprogramowany. I OpenSource (np. MySQL) nie czyni cię odpornym na tak wspaniałe drobiazgi.

Diabeł tkwi w szczegółach, jak mówi stare przysłowie.

Teraz nie jest tak, że nie możesz obejść takich problemów, ale naprawdę nie poleciłbym tego, jeśli twój system będzie złożony (np. Ponad 200 tabel).
Co więcej, w zwykłym komercyjnym otoczeniu (jak to przedstawił Dilbert), po prostu nie otrzymasz tego czasu.

O wiele lepszym podejściem, choć trudniejszym, byłby stół zamykający.
Miałoby to dodatkową zaletę, że działa również na MySQL.
Gdy raz zaimplementujesz funkcję zamykania, będziesz w stanie działać w dodatkowych miejscach w niemalże żadnym momencie.


3
+1 po zwróceniu uwagi na tabele zamknięcia (przynajmniej terminologia, znałem już tę koncepcję). Oto dobry artykuł na ten temat dla innych, którzy mogą być zainteresowani. coderwall.com/p/lixing/closure-tables-for-browsing-trees-in-sql
Źródło Outfast

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.