Implementowanie podtypu podtypu we wzorcu projektowym typu / podtypu z wzajemnie wykluczającymi się podklasami

20

Wprowadzenie

Aby pytanie to było przydatne dla przyszłych czytelników, użyję ogólnego modelu danych, aby zilustrować problem, z którym się zmagam.

Nasz model danych składa się z 3 podmiotów, które będą oznaczone jako A, Boraz C. Aby uprościć sprawę, wszystkie ich atrybuty będą inttypu.

Jednostka Aposiada następujące atrybuty: D, Ei X;

Jednostka Bposiada następujące atrybuty: D, Ei Y;

Jednostka Cma następujące atrybuty: Di Z;

Ponieważ wszystkie podmioty mają wspólny atrybut D, postanowiłem zastosować projekt typu / podtypu .

Ważne: byty wzajemnie się wykluczają! Oznacza to, że jednostka to A, B lub C.

Problem:

Encje Ai Bmają jeszcze jeden wspólny atrybut E, ale ten atrybut nie występuje w encji C.

Pytanie:

Chciałbym użyć opisanej powyżej cechy, aby w miarę możliwości zoptymalizować mój projekt.

Szczerze mówiąc, nie mam pojęcia, jak to zrobić, ani od czego zacząć, stąd ten post.

AlwaysLearningNewStuff
źródło

Odpowiedzi:

6

W zakresie, w jakim to pytanie jest kontynuacją Czy moja implementacja wzorca projektowego typu / podtypu (dla wzajemnie wykluczających się podklas) jest poprawna? , która sama w sobie jest kontynuacją Nie wiem, jak przekształcić zmienną jednostkę w relacyjną tabelę , zapytałbym: co dokładnie próbujesz zoptymalizować? Przechowywanie? Model obiektowy? Złożoność zapytania? Wydajność zapytania? Podczas optymalizacji jednego aspektu względem drugiego występują kompromisy, ponieważ nie można zoptymalizować wszystkich aspektów jednocześnie.

Całkowicie zgadzam się z punktami Remusa dotyczącymi:

  • Każde podejście ma wady i zalety (tj. Zawsze obecny czynnik „zależy”), i
  • Pierwszym priorytetem jest wydajność modelu danych (nieefektywnego modelu danych nie można poprawić za pomocą czystego i / lub wydajnego kodu aplikacji)

To powiedziawszy, wybór, przed którym stoisz, jest pomiędzy następującymi, ułożonymi w kolejności od najmniejszej normalizacji do większości normalizacji:

  • promowanie właściwości Edo tabeli typu podstawowego
  • trzymanie go w wielu tabelach podtypów
  • pełna normalizacja Edo nowej, pośredniej tabeli podklas na tym samym poziomie co C, Ai która Bbędzie bezpośrednio podklasami (odpowiedź @ MDCCL )

Spójrzmy na każdą opcję:

Przenieś właściwość Edo tabeli typu podstawowego

PRO

  • Zredukowana złożoność zapytań dla zapytań potrzeba E, ale nie X, Yalbo Z.
  • Potencjalnie bardziej efektywne dla zapytań, które potrzebują Eale nie X, Ylub Z(zwłaszcza kruszywa zapytań) ze względu na brak JOIN.
  • Potencjał do utworzenia indeksu na (D, E)(a jeśli tak, potencjalnie indeksowany (D, E)filtr, gdzie EntityType <> C, jeśli taki warunek jest dozwolony)

Cons

  • Nie można oznaczyć EjakoNOT NULL
  • Potrzebujesz dodatkowej CHECK CONSTRAINTtabeli typu podstawowego, aby upewnić się, że E IS NULLgdy EntityType = C(choć nie jest to ogromny problem)
  • Trzeba edukować użytkowników modelu danych, dlaczego Emusi być NULL, a nawet powinien być całkowicie ignorowany, gdy EntityType = C.
  • Nieco mniej wydajny, gdy Ejest typu o stałej długości, a duża część wierszy dotyczy EntityType C(tzn. Nie używa Ego zatem NULL), i nie używa ani SPARSEopcji w kolumnie, ani kompresji danych w indeksie klastrowym
  • Potencjalnie mniej wydajny w przypadku zapytań, które nie są potrzebne, Eponieważ obecność Ew tabeli typu podstawowego zwiększy rozmiar każdego wiersza, co z kolei zmniejszy liczbę wierszy, które mogą zmieścić się na stronie danych. Jest to jednak wysoce zależne od dokładnego typu danych EFILLFACTOR, liczby wierszy w tabeli typu bazowego itp.

Zachowaj właściwość Ew każdej tabeli podtypu

PRO

  • Czystszy model danych (tj. Nie musisz się martwić o edukowanie innych, dlaczego kolumna Ew tabeli typu podstawowego nie powinna być używana, ponieważ „tak naprawdę jej nie ma”)
  • Prawdopodobnie bardziej przypomina model obiektowy
  • Może oznaczyć kolumnę tak, NOT NULLjakby była to wymagana właściwość jednostki
  • Nie ma potrzeby stosowania dodatkowych CHECK CONSTRAINTw tabeli typu podstawowego, aby upewnić się, że E IS NULLgdy EntityType = C(choć nie jest to ogromny zysk)

Cons

  • Wymaga DOŁĄCZ do podtypu Tabele, aby uzyskać tę właściwość
  • Potencjalnie nieco mniej wydajny, gdy jest potrzebny E, ze względu na JOIN, w zależności od liczby wierszy A+ Bw przeciwieństwie do liczby wierszy C.
  • Nieco trudniejsze / bardziej skomplikowane dla operacji, które dotyczą wyłącznie podmiotów Ai B(a nie C ) jako tego samego „typu”. Oczywiście można to wyodrębnić za pomocą widoku, który wykonuje UNION ALLmiędzy SELECTtabelą JOINed dla Ainnej SELECTa tabelą JOINed dla B. Że zmniejszy złożoność zapytań SELECT, ale nie tak pomocne INSERTi UPDATEzapytań.
  • W zależności od konkretnych zapytań i częstotliwości ich wykonywania może to być potencjalna nieefektywność w przypadkach, w których posiadanie indeksu (D, E)naprawdę pomogłoby jednemu lub większej liczbie często używanych zapytań, ponieważ nie można ich indeksować razem.

Normalizuj Edo tabeli pośredniej między klasą bazową a A&B

(Proszę zauważyć, że podoba mi się odpowiedź @ MDCCL jako realna alternatywa, w zależności od okoliczności. Poniższe informacje nie mają na celu surowej krytyki tego podejścia, ale jako sposób na dodanie perspektywy - oczywiście mojej - poprzez ocenę w tym samym kontekście, co dwie opcje, które już zaproponowałem. Ułatwi to wyjaśnienie, co postrzegam jako względną różnicę między pełną normalizacją a obecnym podejściem do częściowej normalizacji).

PRO

  • model danych jest w pełni znormalizowany (nie może być w tym nic złego, biorąc pod uwagę, że właśnie do tego służą RDBMS)
  • zmniejszona złożoność zapytań dla zapytań wymagających Ai B, ale nie C(tj. nie ma potrzeby łączenia dwóch zapytań przez UNION ALL)

Cons

  • nieco więcej zajmowanego miejsca ( Bartabela duplikuje identyfikator i pojawia się nowa kolumna BarTypeCode) [nieistotne, ale należy pamiętać]
  • nieznaczny wzrost złożoności zapytań jako dodatkowy JOINjest potrzebny, aby dostać się do jednego Alub drugiegoB
  • zwiększone pole powierzchni do blokowania, głównie włączone INSERT( DELETEmoże być obsługiwane domyślnie poprzez oznaczenie kluczy obcych jako ON CASCADE DELETE), ponieważ transakcja będzie utrzymywana otwarta dłużej na stole klasy podstawowej (tj. Foo) [nieistotne, ale należy pamiętać o tym]
  • brak bezpośredniej wiedzy o rzeczywistym typie - Alub B- w obrębie tabeli klasy podstawowej Foo; to wie tylko typu Br, który może być Aalbo B:

    Oznacza to, że jeśli musisz wykonać zapytania dotyczące ogólnych informacji podstawowych, ale musisz albo skategoryzować według typu jednostki, albo odfiltrować jeden lub więcej typów jednostek, wówczas tabela klasy podstawowej nie ma wystarczającej ilości informacji, w takim przypadku musisz stół. Zmniejszy to także skuteczność indeksowania kolumny.LEFT JOINBarFooTypeCode

  • brak spójnego podejścia do interakcji z A& Bvs C:

    Oznacza to, że jeśli każdy byt odnosi się bezpośrednio do tabeli klasy podstawowej, tak że istnieje tylko jedno DOŁĄCZENIE, aby uzyskać pełny byt, wówczas każdy może szybciej i łatwiej zdobyć znajomość w zakresie pracy z modelem danych. Będzie powszechne podejście do zapytań / procedur przechowywanych, które przyspieszy ich rozwój i zmniejszy prawdopodobieństwo błędów. Spójne podejście ułatwia także dodawanie nowych podtypów w przyszłości.

  • potencjalnie mniej przystosowalny do reguł biznesowych, które zmieniają się z czasem:

    Oznacza to, że rzeczy zawsze się zmieniają, a przejście Edo tabeli klasy podstawowej jest dość łatwe, jeśli stanie się wspólne dla wszystkich podtypów. Łatwo jest również przenieść wspólną właściwość do podtypów, jeśli zmiany w charakterze jednostek powodują, że warto to zmienić. Łatwo jest podzielić podtyp na dwa podtypy (po prostu utworzyć inną SubTypeIDwartość) lub połączyć dwa lub więcej podtypów w jeden. I odwrotnie, co jeśli Epóźniej stałoby się wspólną własnością wszystkich podtypów? Wtedy warstwa pośrednia Bartabeli byłaby bez znaczenia, a dodatkowa złożoność nie byłaby tego warta. Oczywiście nie można wiedzieć, czy taka zmiana nastąpiłaby za 5 czy nawet 10 lat, więc Bartabela niekoniecznie, ani nawet prawdopodobnie nie będzie złym pomysłem (dlatego powiedziałem „ potencjalnie mniej adaptowalny”). To tylko punkty do rozważenia; jest to hazard w obu kierunkach.

  • potencjalnie nieodpowiednie grupowanie:

    To znaczy, tylko dlatego, że Ewłaściwość jest współdzielona między typami jednostek Ai Bnie oznacza tego Ai B powinna być zgrupowana razem. To, że rzeczy „wyglądają” tak samo (tj. Te same właściwości), nie oznacza, że ​​są takie same.

streszczenie

Podobnie jak decyzja, czy / kiedy należy denormalizować, jak najlepiej podejść do tej konkretnej sytuacji, zależy od rozważenia następujących aspektów korzystania z modelu danych i upewnienia się, że korzyści przewyższają koszty:

  • ile rzędów będziesz mieć dla każdego EntityType (spójrz co najmniej 5 lat w dół, zakładając ponadprzeciętny wzrost)
  • ile GB będzie miała każda z tych tabel (typu podstawowego i podtypów) za 5 lat?
  • jaki konkretny typ danych jest właściwością E
  • czy jest to tylko jedna właściwość, czy istnieje kilka, a nawet kilka właściwości
  • jakie zapytania będą potrzebne Ei jak często będą wykonywane
  • jakich zapytań będziesz potrzebować, których nie potrzebujesz Ei jak często będą wykonywane

Myślę, że raczej domyślnie trzymam się Ew osobnych tabelach podtypów, ponieważ jest to przynajmniej „czystsze”. Zastanowiłbym się nad przejściem Edo tabeli typu podstawowego IF: większość wierszy nie dotyczyła EntityType C; a liczba rzędów była co najmniej w milionach; i częściej niż nie wykonywałem zapytań, które były potrzebne Ei / lub zapytań, które skorzystałyby z indeksu przy (D, E)wykonywaniu bardzo często i / lub wymagały wystarczających zasobów systemowych, tak że posiadanie indeksu zmniejsza ogólne wykorzystanie zasobów lub przynajmniej zapobiega gwałtowne wzrosty zużycia zasobów przekraczające dopuszczalne poziomy lub trwające wystarczająco długo, aby spowodować nadmierne blokowanie i / lub wzrost impasu.


AKTUALIZACJA

OP skomentował tę odpowiedź, że:

Moi pracodawcy zmienili logikę biznesową, całkowicie usuwając E!

Zmiana ta jest szczególnie ważna, ponieważ jest to dokładnie to, co opiera się może zdarzyć w „minusy” podsekcji „normalizują Esię do tabeli pośredniczącej między bazowej klasy i A& B” Sekcja powyżej (podpunkt 6). Konkretnym problemem jest to, jak łatwo / trudno jest refaktoryzować model danych, gdy takie zmiany się zdarzają (i zawsze tak się dzieje). Niektórzy twierdzą, że każdy model danych może być refaktoryzowany / zmieniony, więc zacznij od ideału. Ale chociaż na poziomie technicznym prawdą jest, że wszystko można zrefaktoryzować, rzeczywistość sytuacji jest kwestią skali.

Zasoby nie są nieskończone, nie tylko procesor / dysk / pamięć RAM, ale także zasoby programistyczne: czas i pieniądze. Firmy stale ustalają priorytety dla projektów, ponieważ zasoby te są bardzo ograniczone. I dość często (przynajmniej z mojego doświadczenia) projekty mające na celu zwiększenie wydajności (nawet zarówno wydajność systemu, jak i szybszy rozwój / mniej błędów) są traktowane priorytetowo poniżej projektów, które zwiększają funkcjonalność. Choć jest to dla nas frustrujące dla ludzi technicznych, ponieważ rozumiemy, jakie są długoterminowe korzyści z projektów refaktoryzacyjnych, to po prostu charakter działalności sprawia, że ​​mniej techniczni ludzie biznesu łatwiej dostrzegają bezpośredni związek między nową funkcjonalnością a nową dochód. Sprowadza się to do: „wrócimy, aby to naprawić później” == ”

Mając to na uwadze, jeśli rozmiar danych jest na tyle mały, że zmiany mogą być bardzo zapytane, i / lub masz okno konserwacji, które jest wystarczająco długie, aby nie tylko wprowadzić zmiany, ale także wycofać, jeśli coś pójdzie źle, wtedy normalizacja Edo tabeli pośredniej między tabelą klasy podstawowej a tabelami A& Bpodklasy mogłaby działać (choć nadal nie ma bezpośredniej wiedzy o konkretnym typie ( AlubB) w tabeli klasy podstawowej). ALE, jeśli masz w tych tabelach setki milionów wierszy i niewiarygodną ilość kodu odnoszącego się do tabel (kod, który należy przetestować po wprowadzeniu zmian), zwykle opłaca się być bardziej pragmatyczny niż idealistyczny. I z tym środowiskiem miałem do czynienia od lat: 987 milionów wierszy i 615 GB w tabeli klasy podstawowej, rozmieszczonych na 18 serwerach. Tyle tabel uderzyło w te tabele (tabele klasy podstawowej i podklasy), że napotkano duży opór - głównie ze strony kierownictwa, ale czasem reszty zespołu - na wprowadzanie jakichkolwiek zmian ze względu na stopień rozwoju i Zasoby związane z kontrolą jakości, które należałoby przydzielić.

Ponownie więc „najlepsze” podejście można ustalić tylko w zależności od sytuacji: musisz znać swój system (tj. Ile danych i jak odnoszą się wszystkie tabele i kod), jak dokonać refaktoryzacji i ludzi z którym współpracujesz (Twój zespół i ewentualnie kierownictwo - czy możesz uzyskać ich wpisowe na taki projekt?). Są pewne zmiany, o których wspominałem i planowałem przez 1–2 lata, i wziąłem wiele sprintów / wydań, aby wdrożyć może 85% z nich. Ale jeśli masz tylko <1 milion wierszy i nie ma dużo kodu powiązanego z tymi tabelami, prawdopodobnie możesz zacząć od bardziej idealnej / „czystej” strony.

Pamiętaj tylko, niezależnie od tego, którą drogą wybierzesz, zwróć uwagę na to, jak działa ten model przez co najmniej 2 lata (jeśli to możliwe). Zwróć uwagę na to, co zadziałało i co spowodowało ból, nawet jeśli wydawało się to najlepszym pomysłem w tamtym czasie (co oznacza, że ​​musisz także pozwolić sobie na popsuwanie się - wszyscy tak robimy - abyś mógł uczciwie ocenić punkty bólu) ). I zwróć uwagę na to, dlaczego niektóre decyzje działały lub nie, abyś mógł podjąć decyzje, które prawdopodobnie będą „lepsze” następnym razem :-).

Solomon Rutzky
źródło
17

Według Martina Fowlera istnieją 3 podejścia do problemu dziedziczenia tabel:

  • Dziedziczenie pojedynczej tabeli : jedna tabela reprezentuje wszystkie typy. Niewykorzystane atrybuty są zerowane.
  • Dziedziczenie tabeli betonu : Jedna tabela na typ betonu, każda kolumna tabeli dla każdego atrybutu typu. Brak relacji między tabelami.
  • Dziedziczenie tabeli klas : Jedna tabela dla każdego typu, każda tabela ma atrybuty tylko dla nowych, nie odziedziczonych atrybutów. Tabele są powiązane, odzwierciedlając rzeczywistą hierarchię dziedziczenia typów.

Możesz zacząć od nich jako punktu wyjścia do wyszukiwania zalet i wad każdego podejścia. Istotą tego jest to, że wszystkie podejścia mają poważne wady i żadne z nich nie ma przytłaczającej przewagi. Problem ten, jeszcze lepiej znany jako niedopasowanie relacyjnej impedancji obiektu , nie został jeszcze rozwiązany.

Osobiście uważam, że rodzaj problemów, do których może prowadzić zły projekt relacyjny, jest o rząd wielkości poważniejszy niż rodzaj problemów wynikających z projektu typu złego . Zły projekt bazy danych prowadzi do powolnych zapytań, anomalii aktualizacji, eksplozji rozmiaru danych, impasu i braku odpowiedzi aplikacji oraz dziesiątek do setek gigabajtów danych zatopionych w niewłaściwym formacie . Niepoprawne projektowanie prowadzi do trudności w utrzymaniu i aktualizacji kodu , a nie środowiska wykonawczego. Dlatego w mojej książce poprawny projekt relacyjny przebija czystość typu OO w kółko.

Remus Rusanu
źródło
@AlwaysLearningNewStuff Myślę, że to pytanie jest kontynuacją na dba.stackexchange.com/questions/139092 , prawda? W realizacji nie masz zrobić mieć tabeli dziedziczenia.
Remus Rusanu
Tak, zanim zadałem to pytanie, chciałem się upewnić, że zrozumiałem, jak najpierw zaimplementować projekt typu / podtypu. Teraz napotykam wyżej opisany problem, gdy niektóre (ale nie wszystkie!) Podklasy mają wspólne atrybuty. Zastanawiałem się, czy jest coś, co mogę zrobić, aby zoptymalizować model danych w tym przypadku, zamiast lekceważyć ten niuans ...
AlwaysLearningNewStuff
6

Zgodnie z moją interpretacją twoich specyfikacji chcesz znaleźć metodę implementacji dwóch różnych (ale połączonych ) struktur podtypów .

Aby objaśnić podejście do realizacji wspomnianego zadania, dodam do omawianego scenariusza dwa klasyczne typy hipotetycznych typów , które nazywamy Fooi Bar, które szczegółowo omówię poniżej.

Zasady biznesowe

Oto kilka stwierdzeń, które pomogą mi stworzyć model logiczny:

  • A Foo is either one Bar or one C
  • A Foo is categorized by one FooType
  • A Bar is either one A or one C
  • A Bar is classified by one BarType

Model logiczny

Następnie wynikowy model logiczny IDEF1X [1] pokazano na rysunku 1 (można go również pobrać z Dropbox jako plik PDF ):

Ryc. 1 - Hipotetyczny model danych relacji podtyp i podtyp

Dodatek Foo and Bar

Nie dodałem Foo i Barżeby model wyglądał lepiej, ale żeby był bardziej wyrazisty. Uważam, że są one ważne z następujących powodów:

  • Ponieważ Ai Bdzielę się nazwanym atrybutem E, ta funkcja sugeruje , że są to typy podobieństwa odrębnego (ale pokrewnego) rodzaju pojęcia , zdarzenia , osoby , miary itp., Które przedstawiłem za pomocą Bartypu podrzędności, który z kolei jest rodzaj podobieństwa Foo, który posiadaD atrybut na górze hierarchii.

  • Ponieważ Cdzieli tylko jeden atrybut z pozostałymi omawianymi typami bytu, tj. DAspekt ten sugeruje , że jest to rodzaj podobieństwa innego rodzaju koncepcji , zdarzenia , osoby , pomiaru itp., Dlatego przedstawiłem tę okoliczność na podstawieFoo Super typu jednostki.

Są to jednak tylko założenia, a ponieważ relacyjna baza danych ma dokładnie odzwierciedlać semantykę określonego kontekstu biznesowego , musisz zidentyfikować i sklasyfikować wszystkie interesujące rzeczy w Twojej konkretnej domenie, abyś mógł dokładnie uchwycić więcej znaczenia .

Ważne czynniki na etapie projektowania

Warto wiedzieć, że odkładając na bok całą terminologię, wyłączny klaster typu podtyp jest zwykłym związkiem. Opiszmy sytuację w następujący sposób:

  • Każde wystąpienie wyłącznego rodzaju podrzędności jest powiązane tylko z jednym dopełnieniem typu podległości .

Tak więc w tych przypadkach istnieje zgodność (lub liczność) jeden do jednego (1: 1).

Jak wiadomo z poprzednich postów, atrybut dyskryminujący (kolumna, gdy jest zaimplementowany) odgrywa nadrzędną rolę podczas tworzenia powiązania tego rodzaju, ponieważ wskazuje on poprawną instancję podtypu, z którą połączony jest nadtyp . migracja z klucz podstawowy z (i) supertypem do (ii) podtypy również pierwszorzędne znaczenie.

Betonowa struktura DDL

A potem napisałem strukturę DDL opartą na modelu logicznym przedstawionym powyżej:

CREATE TABLE FooType -- Look-up table.
(
    FooTypeCode     CHAR(2)  NOT NULL,
    Description     CHAR(90) NOT NULL, 
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_FooType             PRIMARY KEY (FooTypeCode),
    CONSTRAINT AK_FooType_Description UNIQUE      (Description)
);

CREATE TABLE Foo -- Supertype
(
    FooId           INT      NOT NULL, -- This PK migrates (1) to ‘Bar’ as ‘BarId’, (2) to ‘A’ as ‘AId’, (3) to ‘B’ as ‘BId’, and (4) to ‘C’ as ‘CId’.
    FooTypeCode     CHAR(2)  NOT NULL, -- Discriminator column.
    D               INT      NOT NULL, -- Column that applies to ‘Bar’ (and therefore to ‘A’ and ‘B’) and ‘C’.
    CreatedDateTime DATETIME NOT NULL,
    CONSTRAINT PK_Foo                 PRIMARY KEY (FooId),
    CONSTRAINT FK_from_Foo_to_FooType FOREIGN KEY (FooTypeCode)
        REFERENCES FooType (FooTypeCode)
);

CREATE TABLE BarType -- Look-up table.
(
    BarTypeCode CHAR(1)  NOT NULL,  
    Description CHAR(90) NOT NULL,  
    CONSTRAINT PK_BarType             PRIMARY KEY (BarTypeCode),
    CONSTRAINT AK_BarType_Description UNIQUE      (Description)
);

CREATE TABLE Bar -- Subtype of ‘Foo’.
(
    BarId       INT     NOT NULL, -- PK and FK.
    BarTypeCode CHAR(1) NOT NULL, -- Discriminator column. 
    E           INT     NOT NULL, -- Column that applies to ‘A’ and ‘B’.
    CONSTRAINT PK_Bar             PRIMARY KEY (BarId),
    CONSTRAINT FK_from_Bar_to_Foo FOREIGN KEY (BarId)
        REFERENCES Foo (FooId),
    CONSTRAINT FK_from_Bar_to_BarType FOREIGN KEY (BarTypeCode)
        REFERENCES BarType (BarTypeCode)    
);

CREATE TABLE A -- Subtype of ‘Bar’.
(
    AId INT NOT NULL, -- PK and FK.
    X   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_A             PRIMARY KEY (AId),
    CONSTRAINT FK_from_A_to_Bar FOREIGN KEY (AId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE B -- (1) Subtype of ‘Bar’ and (2) supertype of ‘A’ and ‘B’.
(
    BId INT NOT NULL, -- PK and FK.
    Y   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_B             PRIMARY KEY (BId),
    CONSTRAINT FK_from_B_to_Bar FOREIGN KEY (BId)
        REFERENCES Bar (BarId)  
);

CREATE TABLE C -- Subtype of ‘Foo’.
(
    CId INT NOT NULL, -- PK and FK.
    Z   INT NOT NULL, -- Particular column.  
    CONSTRAINT PK_C             PRIMARY KEY (CId),
    CONSTRAINT FK_from_C_to_Foo FOREIGN KEY (FooId)
        REFERENCES Foo (FooId)  
);

Dzięki tej strukturze unikasz przechowywania znaków NULL w tabelach podstawowych (lub relacjach ), co wprowadziłoby niejednoznaczność do bazy danych.

Uczciwość, spójność i inne względy

Po wdrożeniu bazy danych należy upewnić się, że (a) każdy wyłączny wiersz nadtypu jest zawsze uzupełniany przez odpowiedni odpowiednik podtypu, a z kolei gwarantuje, że (b) taki wiersz podtypu jest zgodny z wartością zawartą w kolumnie dyskryminatora nadtypu . Dlatego bardzo wygodnie jest stosować ACID TRANSACTIONS, aby upewnić się, że warunki te są spełnione w bazie danych.

Nie należy rezygnować z logicznej solidności, samoekspresji i dokładności bazy danych, są to aspekty, które zdecydowanie sprawiają, że baza danych jest bardziej solidna.

Dwie wcześniej opublikowane odpowiedzi już zawierają istotne punkty, które z pewnością warto wziąć pod uwagę przy projektowaniu, tworzeniu i zarządzaniu bazą danych i jej aplikacjami.

Pobieranie danych za pomocą definicji VIEW

Można skonfigurować niektóre widoki, które łączą kolumny różnych grup podtypów i typów , dzięki czemu można pobrać dostępne dane bez, np. Pisania za każdym razem niezbędnych klauzul JOIN. W ten sposób możesz z łatwością WYBIERAĆ bezpośrednio Z WIDOKU ( zależność pochodna lub tabela ).

Jak widać, „Ted” Codd był niewątpliwie genialny. Narzędzia, które zapisał, są dość mocne i eleganckie, i oczywiście są dobrze zintegrowane ze sobą.

Powiązane zasoby

Jeśli chcesz przeanalizować obszerną bazę danych, która obejmuje relacje nadtyp-podtyp, możesz znaleźć niezwykłe odpowiedzi zaproponowane przez @PerformanceDBA na następujące pytania dotyczące przepełnienia stosu:


Uwaga

1. Definicja integracji dla modelowania informacji ( IDEF1X ) jest wysoce zalecaną techniką modelowania danych, która została ustanowiona jako standard w grudniu 1993 r. Przez Narodowy Instytut Norm i Technologii Stanów Zjednoczonych ( NIST ). Jest solidnie oparty na (a) wczesnym materiale teoretycznym autorstwa dr EF Codda; od (b) do związków encji świetle danych, opracowanych przez dr PP Chen ; a także w (c) Logical Database Design Technique, stworzonej przez Roberta G. Browna. Warto zauważyć, że IDEF1X został sformalizowany za pomocą logiki pierwszego rzędu.

MDCCL
źródło
Moi pracodawcy zmienili logikę biznesową, usuwając Ecałkowicie! Powodem przyjęcia odpowiedzi użytkownika srutzky jest to, że zapewnia on dobre punkty, które pomagają mi podjąć decyzję o wyborze najbardziej efektywnej trasy. Gdyby nie to, zaakceptowałbym twoją odpowiedź. Wcześniej głosowałem za odpowiedzią. Dzięki jeszcze raz!
AlwaysLearningNewStuff