Czy to niedorzeczny sposób na ustrukturyzowanie schematu DB, czy też czegoś mi brakuje?


61

Wykonałem sporo pracy z relacyjnymi bazami danych i myślę, że całkiem dobrze rozumiem podstawowe koncepcje dobrego projektowania schematów. Niedawno miałem za zadanie przejąć projekt, w którym DB zaprojektował wysoce opłacany konsultant. Daj mi znać, jeśli mój instynkt jelitowy - „WTF ??!?” - jest uzasadniony, czy ten facet jest tak genialny, że działa poza moim królestwem?

DB, o której mowa, to wewnętrzna aplikacja służąca do wprowadzania żądań od pracowników. Wystarczy spojrzeć na jego niewielką część, aby uzyskać informacje o użytkownikach i informacje o złożonym żądaniu. Zaprojektowałbym to tak:

Tabela użytkowników:

UserID (primary Key, indexed, no dupes)
FirstName
LastName
Department

Tabela zapytań

RequestID (primary Key, indexed, no dupes)
<...> various data fields containing request details
UserID -- foreign key associated with User table

Proste, prawda?

Konsultant zaprojektował to tak (z przykładowymi danymi):

UsersTable

UserID  FirstName   LastName
234     John        Doe
516     Jane        Doe
123     Foo         Bar

DepartmentsTable

DepartmentID   Name
1              Sales
2              HR
3              IT

UserDepartmentTable

UserDepartmentID   UserID   Department
1                  234      2
2                  516      2
3                  123      1

RequestTable

RequestID   UserID   <...>
1           516      blah
2           516      blah
3           234      blah

Cała baza danych jest zbudowana w ten sposób, a każdy kawałek danych jest zamknięty w swojej własnej tabeli, z numerycznymi identyfikatorami łączącymi wszystko razem. Najwyraźniej konsultant czytał o OLAP i chciał „szybkości wyszukiwania liczb całkowitych”

Ma również dużą liczbę procedur przechowywanych, aby odwołać się do wszystkich tych tabel.

Czy jest to poprawny projekt dla małej lub średniej bazy danych SQL?

Dzięki za komentarze / odpowiedzi ...


12
Och, chłopcze, jeśli to powoduje, że mówisz WTF, to prawdopodobnie nie widziałeś tabel z ponad 200 kolumnami i procedurami przechowywanymi dłuższymi niż 1000 linii.
Job

42
+1 za brak usuwania po zawstydzeniu. Dziękujemy za pozostawienie tego, aby inni mogli się uczyć.
Wayne Koorts

2
@Job - właściwie nie mam - z zawodu nie jestem DBA (do tej pory całkiem oczywiste! Lol), więc mój próg SQL WTF jest dość niski. Chociaż całkowicie nie rozumiem projektu konsultanta, mam umiejętności WTF. Czy miałeś kiedyś dzień, w którym czujesz się głupi ?
Jim

9
@Jim: Gratulacje, zmieniłeś głupi dzień w dzień oświecony .
Wayne Koorts

3
Przeklnij tych wysoko opłacanych konsultantów!
davidsleeps 30.09.11

Odpowiedzi:


73

Ma to dla mnie sens. Jest po prostu bardzo znormalizowany, co zapewnia dużą elastyczność, której inaczej byś nie miał. Dane zdenormalizowane to ból w tyłku.


twoja odpowiedź ma doskonały sens, a patrząc na moje pytanie i schemat, może mnie to zdezorientowało. Znacząco uprościłem przykład mojego pytania, ale widzę, jak brzmi ta koncepcja - on po prostu dzieli rzeczy znacznie bardziej niż ja. Westchnienie, myślę, że to dobrze, że nie jestem DBA! :)
Jim

Naucz się projektować według reguły dziesięciu minut: „To, co jest prawdą, prawdopodobnie nie nastąpi za dziesięć minut”. Upewnij się, że twoje projekty poradzą sobie ze zmianami.
Blrfl,

1
Ten schemat ma tę zaletę, że po wstawieniu pracownika jego dział musi istnieć.
Simon Richter

@SimonRichter: To nieprawda. Pracownik może zostać utworzony bez żadnego działu, a także w odwrotnej kolejności.
Daniel Dinnyes,

@ SimonRichter Zaletą tego projektu jest po pierwsze, że Departament jest odrębną jednostką, a po drugie, że istnieje relacja wiele do wielu między Departamentem a Pracownikiem, w przeciwieństwie do przykładu PO, gdzie było to „wiele- to-one-ish ”(nie można powiedzieć wiele-do-jednego, ponieważ nie było oddzielnej jednostki Departamentu, o której mówiono, że można ją nazwać relacją).
Daniel Dinnyes,

48

Nie sądzę, że albo WTF jest uzasadnione, albo że facet robi jakiś szalony genialny projekt - to dość standardowa normalizacja bazy danych.

Powodem dla tabeli działów jest to, że jeśli nie umieścisz działów w osobnej tabeli, będziesz musiał kontaktować się z użytkownikami w działach „Sprzedaż”, „Sprzedaż”, „Sprzedawcy”, „Żagle” i „Sprzedaż”, chyba że zrobisz coś, aby temu zapobiec. A posiadanie dodatkowego stołu to (część) najlepszy sposób, jaki wiem, aby to zrobić.

To, czy powinna istnieć tabela UserDepartment, jest trudniejsze, co oczywiście oznacza, że ​​żadna decyzja nie jest szalona. Z jednej strony jest to ból, gdy cały projekt stołu i logika zakładają jeden dział na użytkownika, a potem to się zmienia, z drugiej strony wykonywanie dodatkowego łączenia bez powodu przez lata i lata jest realną możliwością, a także bólem.

Osobiście zgodziłbym się z tobą, że tabela UserDepartment prawdopodobnie przesadza. Nawet jeśli jest uwzględnione, są szanse, że z czasem ludzie będą pisać zapytania, które zakładają, że jest tylko jeden użytkownik na dział, więc skończysz z najgorszym z obu światów - dodatkowe połączenie bez żadnego powodu przed potrzebowaniem stołu, i kod i tak nie działa, gdy dozwolony jest więcej niż jeden dział na użytkownika.

EDYCJA - Kluczowym czynnikiem decydującym o tym, czy należy wspierać relację wielu do wielu, jest to, czy reguły biznesowe są jasne. Jeśli nie masz pojęcia, jak mógłby działać użytkownik w wielu działach, dodanie tabeli nie ma sensu, ponieważ Twój kod nie jest w stanie poprawnie obsłużyć przypadków, w których użytkownik jest w wielu działach.

Wyobraź sobie, że na wszelki wypadek zezwoliłeś na wiele działów na użytkownika. Następnie zaimplementowano regułę biznesową do przypisywania prowizji na podstawie działu. Następnie dozwolonych było wiele działów. Na szczęście miałeś również zdolność przewidywania, aby napisać kod prowizji w sposób uwzględniający to. Niestety, dodałeś prowizje z każdego działu dla użytkowników w obu. Kierownictwo chciało, abyś oparł się na roli osoby przy każdej sprzedaży. Więc ile dobrego było z wyprzedzeniem przy stole? Co z innymi stolikami, które miałeś „na wszelki wypadek”, które w ogóle nigdy nie są potrzebne?

PÓŹNA EDYCJA - Innym powodem, dla którego konsultant mógł chcieć dodać wszystkie tabele pośredniczące, jest odpowiedź na to pytanie uzupełniające , na które odpowiedzi podaje kilka powodów, dla których refaktoryzacja bazy danych jest zwykle trudniejsza niż kod refaktoryzacji, co skłoniłoby cię do podejście „wstaw wszystkie tabele, których możesz potrzebować”.


Wydaje mi się, że wyraziłeś słowami, czym była moja WTF - facet używa TON tych stolików, a to wydawało mi się takie głupie. Teraz, kiedy podzieliłem go na znacznie mniejszy przykład tego pytania, czuję się głupio, gdy je opublikowałem, ponieważ nie wydaje się to takie złe.
Jim

5
Jak widać z wielu komentarzy, istnieje zdrowy sceptycyzm co do tego, że „zawsze będzie tylko jeden X na Y”. Konsultant ukrywa się przed skargami „dlaczego może być tylko jeden X na Y”. Niektóre z nich prawdopodobnie pojawią się. Ale nie będzie odpowiedzialny za utrzymanie kodu, który ma wiele złączeń (nie jest tak źle, ale trudniej) i który musi być poprawny w stosunku do reguł biznesowych, które jeszcze nie istnieją (złe) - wyobraź sobie pytanie „dlaczego użytkownicy otrzymują WSZYSTKIE uprawnienia z każdego działu, powinny uzyskać NAJNIŻSZE z każdego uprawnienia ”lub jakieś inne.
psr

@psr Myślę, że istnieje literówka: czy „zapytania, które zakładają, że w danym dziale jest tylko jeden użytkownik, powinny być„ zapytaniami, które zakładają, że użytkownik jest tylko w jednym departamencie ”?
BiAiB

@BiAiB - masz rację, właśnie to chciałem powiedzieć.
psr

14

Jeśli wymaga się posiadania wielu działów na użytkownika, ten projekt ma sens. Jedyną przeszkodą jest UserDepartmentTableposiadanie klucza zastępczego, UserDepartmentIDktóry nie jest potrzebny (po prostu utwórz klucz złożony UserIdi DepartmentIdzłożony).

Jeśli użytkownik należy tylko do jednego działu, Twój projekt ma sens (choć tabela przeglądów działów nadal byłaby dobra).


18
... Aż do więcej niż jednego działu jest możliwe na użytkownika.
Blrfl,

1
Dokładnie @Blrfl. Dzisiaj nie stanie się jutro jutrzejszym CEO-ma-tętniaka-ponieważ-to-nie-robi-to-to.
Adam Crossland,

2
Częścią decydowania o tym, co jest warte takiego leczenia, jest zrozumienie problematyki. W niektórych aplikacjach może być ważne, aby wiedzieć, że pracownik nr 3804 był znany firmie jako Ann Smith i Ann Jones (po ślubie), co sprawiłoby, że normalizacja nazwiska z tabeli pracowników była rozsądnym posunięciem. W przypadku Jima warto rozszerzyć tabelę przerywników, aby zachować historię, aby jeśli Ann przeniosła się z działu HR do działu IT, fakt, że stare zapytanie powiązane z nią mogło odzwierciedlać, że tak naprawdę było to żądanie HR, a nie IT.
Blrfl,

8
YAGNI - bazy danych można refaktoryzować.
JeffO

2
@Oded, Niektóre programy mapujące ORM, takie jak Entity Framework, nie działają dobrze z tabelami, które mają złożony klucz podstawowy.
wałek klonowy

5

Niektóre wymagania nie są jasne w twoim pytaniu. Prawidłowa odpowiedź zależy od tego, czego chce twój klient - gdybym był tobą, zapytałbym klienta o to:

0-Jaka jest różnica między użytkownikiem a pracownikiem?

1-Zakładając, że pracownik = użytkownik, co jeśli pracownik zmieni działy?

2-Czy grupa pracowników może złożyć 1 wniosek?

3-Czy pracownik może należeć do więcej niż jednego działu? Co z CEO

4-Czy jest podzbiór pracowników, którzy mogą składać wnioski?

5-Co stanie się z żądaniem, gdy rekord pracownika zostanie usunięty (jeśli w ogóle)?

6-Czy możesz usunąć prośbę? Co dzieje się po usunięciu żądania (upewnij się, że nie usuwasz rekordu pracownika przez RI)

7-Czy pracownik może złożyć „to samo” żądanie więcej niż jeden raz (zdefiniować „to samo”)

8-Jak obsługiwać wnioski o odejście pracowników z firmy (anulować lub usunąć prośby?)

Może być więcej pytań, ale moim zdaniem rozwiązanie zależy od dokładnych wymagań i zakresu projektu. Po ustaleniu schemat można uzyskać bezpośrednio. W związku z tym oba przedstawione rozwiązania mogą być poprawne.


+1 to świetne pytania, które należy wyjaśnić przed zaprojektowaniem tego typu schematu. Lubię twój przepływ logiki.

@ Surfer513: Doceniam twój miły komentarz.
NoChance 30.09.11

1

Chciałbym dodać kilka uwag do formularza, które wyraźnie mówią o niektórych potencjalnych zaletach korzystania ze stołu do łączenia w sposób, w jaki zrobił to twój wysoko opłacany konsultant.

  • Prawidłowo zindeksowane (np. Jeśli UserDepartmentTable indeksuje dwa klucze obce), występuje tylko niewielka utrata wydajności takiej tabeli łączenia, ponieważ klucze obce nie są unikalne. Jeśli gwarantowane są unikatowe klucze obce, to według małej teorii baz danych, której znam, wyszukiwanie UserDepartmentTable.Departmentnie jest „trudniejsze” niż wyszukiwanie jakiejkolwiek innej kolumny w Usertabeli.
  • Tabela łączenia daje większą elastyczność w ustawianiu innych informacji o powiązaniu między użytkownikiem a działem (np. Znaczniki czasu podczas tworzenia).
  • Tabela łączenia pozwala dość łatwo „wersjonować” powiązanie (np. Gdy użytkownik zmienia działy, wywołuje flagę indeksu logicznego typu „ UserDepartmentTable.Activefałsz” i tworzy nowe aktywne powiązanie). Możliwe jest również wersjonowanie powiązań departamentów z modelem z dwoma tabelami (tylko użytkownik i dział), ale jest to trudniejsze i wymaga dodania co najmniej jednej kolumny lub wykonania akrobatyki bazy danych, aby uniknąć duplikowania kluczy podstawowych.
  • Pozwala dość łatwo przypisać skojarzenia „jeden do wielu”, „wiele do jednego” lub „wiele do wielu”.

Biorąc to pod uwagę, istnieje kilka powodów, aby NIE robić tego, co zrobił twój wysoko opłacany konsultant.

  • Wszystkie powyższe korzyści przewidują możliwe przyszłe potrzeby, nadmiernie komplikując rzeczy na dzień dzisiejszy. Nie jest zgodny z YAGNI. Późniejsze napisanie migracji, która przenosi się z modelu z dwoma tabelami do modelu z tabelą łączenia, jest banalne. Możesz to zrobić, gdy pojawi się potrzeba biznesowa. Zrobienie tego wcześniej może być mylące.
  • To dezorientuje innych programistów. Chociaż tak, powiedziałbym, że oczekiwaniem od webmastera twojej postury (gdzie przeglądasz decyzje konsultantów) byłoby zrozumienie i rozpoznanie tabeli dołączania, jest to jednak bardziej skomplikowane niż to konieczne i biorąc pod uwagę brak potrzeby biznesowej, powoduje zamieszanie.

niezła analiza - nie powiedziałbym jednak, że nie mam żadnej postury jako programista w mojej codziennej pracy, z wyjątkiem tego, że jestem tu jedynym, który wie cokolwiek o db / c # / vb / etc ... więc zgadnij, że jestem częścią domyślnie dev czas. jest to dość mały projekt, więc konsultanci z samej liczby stolików i dołączeń opuścili mnie mówiąc „wtf” (ale dzięki tobie świetny ludu mówię teraz „oic ...”)
Jim

Całkiem stary temat, ale wciąż istotny ... refaktoryzacja może być bardzo trudna, wyobraź sobie, że potrzebujesz wielu działów w przyszłości zamiast jednego, ale masz tylko identyfikator działu w Użytkownicy jako FK. Najprawdopodobniej skończysz z duplikatami odsyłaczy (Users.DeptID i UsersDepartmentsTable) lub kompletnymi śmieciami, takimi jak listy rozdzielone przecinkami w Users.DeptID lub XML. Nie można łatwo dodać poprawnego rozwiązania, jak sugerują YAGNI lub KISS, ale byłoby to utrudnione.
Erik Hart,

0

Bez pełnej struktury potrzebnych informacji nie mogę powiedzieć, czy to okropne, czy nie. Ale przynajmniej pokazany kawałek nie jest w stylu „WTF”. Wydaje się, że jest to trzecia normalna forma struktury danych (teoretycznie mamy też czwartą i piątą również)

Niektóre rozmowy mogą zawierać miejsce dla UserDepartmentTable między dwiema szkołami „naturalnych” i „sztucznych” kluczy w pokazanym fragmencie. Nic więcej, jak widzę

Normalizacja jest zasadą dobrego dewelopera / projektanta DB z wielu powodów, * normalizacje * de * są czasem stosowane w trakcie rozwoju głównie w celu szybkiego wygrania

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.