Ist dies eine lächerliche Art, ein DB-Schema zu strukturieren, oder fehlt mir etwas komplett?

61

Ich habe ziemlich viel mit relationalen Datenbanken gearbeitet und denke, ich verstehe die Grundkonzepte eines guten Schemaentwurfs ziemlich gut. Vor kurzem wurde ich beauftragt, ein Projekt zu übernehmen, bei dem die DB von einem hochbezahlten Berater entworfen wurde. Bitte lassen Sie mich wissen, ob mein Bauchgefühl - "WTF ??!?" - ist gerechtfertigt, oder ist dieser Typ so ein Genie, dass er außerhalb meines Reiches operiert?

Bei der DB handelt es sich um eine Inhouse-App, mit der Anfragen von Mitarbeitern erfasst werden. Wenn Sie sich nur einen kleinen Abschnitt davon ansehen, erhalten Sie Informationen zu den Benutzern und zu der Anforderung, die gestellt wird. Ich würde das so gestalten:

Benutzertabelle:

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

Tisch anfordern

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

Einfach, richtig?

Berater gestaltet es so (mit Beispieldaten):

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

Die gesamte Datenbank ist so aufgebaut, dass jedes Datenelement in einer eigenen Tabelle zusammengefasst ist und numerische IDs alles miteinander verbinden. Anscheinend hatte der Berater über OLAP gelesen und wollte die "Geschwindigkeit der Ganzzahlensuche"

Er verfügt auch über eine große Anzahl gespeicherter Prozeduren, um auf alle diese Tabellen zu verweisen.

Ist dies ein gültiger Entwurf für eine kleine bis mittelgroße SQL-Datenbank?

Danke für Kommentare / Antworten ...

Jim
quelle
12
Oh Mann, wenn Sie damit WTF sagen, haben Sie wahrscheinlich noch keine Tabellen mit mehr als 200 Spalten und gespeicherten Prozeduren gesehen, die länger als 1000 Zeilen sind.
Job
42
+1 für nicht löschen, nachdem Sie sich verlegen gefühlt haben. Vielen Dank, dass Sie dies verlassen, damit andere lernen können.
Wayne Koorts
2
@Job - eigentlich habe ich nicht - ich bin kein DBA von Beruf (ziemlich offensichtlich jetzt! Lol), also ist mein SQL WTF-Schwellenwert ziemlich niedrig. Obwohl ich den Punkt des Beraterentwurfs völlig verfehlt habe, habe ich meine eigenen Fähigkeiten unter Beweis gestellt. Haben Sie jemals einen Tag, an dem Sie sich einfach nur dumm fühlen ?
Jim
9
@ Jim: Herzlichen Glückwunsch, Sie haben ein einge stumm Tag in einen aufgeklärten Tag.
Wayne Koorts
3
Verfluche diese hochbezahlten Berater!
Davidsleeps

Antworten:

73

Macht für mich vollkommen Sinn. Es ist einfach sehr normalisiert, was viel Flexibilität verleiht, die Sie sonst nicht hätten. De-normalisierte Daten sind ein Schmerz im Hintern.

Blrfl
quelle
Ihre Antwort macht vollkommen Sinn, und wenn Sie meine Frage und das Schema durchsehen, ist es vielleicht nur die bloße Anzahl von Tabellen, die er verwendet, die mich verwirrt. Ich habe das Beispiel für meine Frage stark vereinfacht, aber ich sehe, wie gut das Konzept ist - er spaltet die Dinge nur viel mehr ab als ich. Seufz, ich denke, es ist gut, dass ich kein DBA bin! :)
Jim
Lernen Sie das Entwerfen nach der Zehn-Minuten-Regel: "Was jetzt gilt, wird wahrscheinlich nicht in zehn Minuten sein." Stellen Sie sicher, dass Ihre Designs mit Änderungen umgehen können.
Blrfl
1
Dieses Schema hat tatsächlich den Vorteil, dass beim Einfügen eines Mitarbeiters dessen Abteilung vorhanden sein muss.
Simon Richter
@ SimonRichter: Es ist nicht wahr. Der Mitarbeiter kann erstellt werden, ohne dass eine Abteilung vorhanden ist, und auch umgekehrt.
Daniel Dinnyes
@SimonRichter Der Vorteil dieses Entwurfs besteht zum einen darin, dass die Abteilung eine separate Einheit ist, und zum anderen besteht im Gegensatz zum OP-Beispiel, bei dem es sich um eine "vielschichtige" Beziehung zwischen Abteilung und Mitarbeiter handelt. to-one-ish ".
Daniel Dinnyes
48

Ich glaube nicht, dass eine WTF gerechtfertigt ist oder dass der Typ irgendeine geniale Art von Design macht - es ist eine ziemlich normale Datenbanknormalisierung.

Der Grund für die Abteilungstabelle ist, dass Sie, wenn Sie die Abteilungen nicht in einer separaten Tabelle ablegen, mit Benutzern in den Abteilungen "Verkauf", "Verkauf", "Verkäufer", "Segel" und "Verkauf" arbeiten müssen. es sei denn, Sie tun etwas, um dies zu verhindern. Und den Extratisch zu haben, ist der beste Weg, das zu tun.

Ob es eine UserDepartment-Tabelle geben soll, ist ein härterer Aufruf, was natürlich bedeutet, dass keine der beiden Entscheidungen aus dem Ruder läuft und verrückt ist. Einerseits ist es eine Qual, wenn all Ihre Tabellenkonstruktion und -logik eine Abteilung pro Benutzer angenommen hat und sich dann ändert, andererseits ist es eine echte Möglichkeit und auch eine Qual, jahrelang ohne Grund einen zusätzlichen Join durchzuführen.

Ich persönlich würde Ihnen zustimmen, dass die UserDepartment-Tabelle wahrscheinlich zu viel ist. Auch wenn es enthalten ist, besteht die Möglichkeit, dass die Leute im Laufe der Zeit Abfragen schreiben, bei denen davon ausgegangen wird, dass es nur einen Benutzer pro Abteilung gibt, sodass Sie am Ende das Schlimmste aus beiden Welten haben - ein zusätzlicher Join ohne Grund, bevor Sie den Tisch benötigen, und Code funktioniert sowieso nicht, wenn mehr als eine Abteilung pro Benutzer zulässig ist.

BEARBEITEN - Ein Schlüsselfaktor für die Unterstützung der Viele-zu-Viele-Beziehung ist, ob die Geschäftsregeln klar sind. Wenn Sie nicht wissen, wie ein Benutzer in mehreren Abteilungen arbeiten würde, macht das Hinzufügen der Tabelle nicht viel Sinn, da Ihr Code möglicherweise die Fälle nicht richtig handhaben kann, in denen sich ein Benutzer in mehreren Abteilungen befindet.

Stellen Sie sich vor, Sie hätten für alle Fälle viele Abteilungen pro Benutzer zugelassen. Anschließend haben Sie eine Geschäftsregel für die Zuordnung von Provisionen basierend auf der Abteilung implementiert. Dann waren mehrere Abteilungen erlaubt. Glücklicherweise hatten Sie auch die Voraussicht, Ihren Provisionscode so zu schreiben, dass dies berücksichtigt wurde. Leider haben Sie die Provisionen aus jeder Abteilung für Benutzer in beiden hinzugefügt . Das Management wollte, dass Sie sich bei jedem Verkauf auf die Rolle der Personen stützen. Wie gut war es also, den Tisch im Voraus zu haben? Was ist mit den anderen Tischen, die Sie "nur für den Fall" hatten, dass sie überhaupt nicht benötigt werden?

SPÄTERE BEARBEITUNG - Ein weiterer Grund, warum der Berater möglicherweise alle diese Zwischentabellen hinzufügen wollte, wird in dieser Folgefrage angesprochen. Die Antworten geben einige Gründe an, warum das Refactoring einer Datenbank in der Regel schwieriger ist als das Refactoring von Code, was Sie tendenziell drängt der Ansatz "Setzen Sie alle Tabellen ein, die Sie jemals benötigen könnten".

bA
quelle
Ich denke, Sie haben in Worte gefasst, was meine WTF war - der Typ benutzt Tonnen von diesen Zwischentischen, und es kam mir einfach so dumm vor. Jetzt, wo ich es in ein viel kleineres Beispiel für diese Frage zerlegt habe, finde ich es ziemlich dumm, es zu posten, da es nicht so schlimm zu sein scheint.
Jim
5
Wie Sie an vielen Kommentaren sehen können, gibt es eine gesunde Skepsis gegenüber "es wird immer nur ein X pro Y geben" -Kommentare. Der Berater deckt sich damit ab, dass "wie kommt es, dass es nur ein X pro Y geben kann". Einige davon werden wahrscheinlich auftauchen. Aber er ist nicht dafür verantwortlich, Code zu pflegen, der viele Verknüpfungen hat (nicht schlecht, aber schwerer) und der gegen Geschäftsregeln korrekt sein muss, die noch nicht existieren (schlecht) - stellen Sie sich die Frage "Warum bekommen Benutzer ALLES?" die Berechtigungen von jeder Abteilung, sollten sie das NIEDRIGSTE von jeder Berechtigung bekommen "oder so.
PSR
@psr Ich denke, es gibt einen Tippfehler: Sollten nicht "Abfragen, bei denen angenommen wird, dass es nur einen Benutzer pro Abteilung gibt" "Abfragen, bei denen angenommen wird, dass sich ein Benutzer nur in einer Abteilung befindet"?
BiAiB
@BiAiB - Sie haben Recht, das wollte ich sagen.
PSR
14

Wenn mehrere Abteilungen pro Benutzer erforderlich sein sollen, ist dieses Design sinnvoll. Der einzige Nachteil dabei ist, UserDepartmentTabledass ein Ersatzschlüssel UserDepartmentIDnicht benötigt wird (machen Sie einfach den UserIdund DepartmentIdeinen zusammengesetzten Primärschlüssel).

Wenn ein Benutzer immer nur einer Abteilung angehört, ist Ihr Entwurf sinnvoll (obwohl eine Abteilungsnachschlagetabelle immer noch eine gute Sache wäre).

Oded
quelle
18
... bis mehr als eine Abteilung pro Benutzer möglich ist.
Blrfl
1
Genau, @Blrfl. Das, was heute nicht passieren wird, ist das Aneurysma, das der CEO von morgen hat, weil er es nicht tut.
Adam Crossland
2
Ein Teil der Entscheidung, was dieser Art von Behandlung würdig ist, ist das Verstehen der Problemdomäne. In einigen Anwendungen ist es möglicherweise wichtig zu wissen, dass Mitarbeiter Nr. 3804 dem Unternehmen als Ann Smith und Ann Jones (nach der Heirat) bekannt ist, was eine Normalisierung des Namens aus der Tabelle der Mitarbeiter zu einer vernünftigen Sache machen würde. In Jims Fall könnte es sich lohnen, die Breaker-Tabelle zu erweitern, um eine Historie zu führen. Wenn Ann von HR zu IT wechselt, könnte die Tatsache, dass eine alte Anfrage an sie gebunden ist, widerspiegeln, dass es sich wirklich um die Anfrage von HR und nicht um die von IT handelt.
Blrfl
8
YAGNI - Datenbanken können überarbeitet werden.
JeffO
2
@Oded, Einige ORM-Mapper wie Entity Framework funktionieren nicht gut mit Tabellen, die einen zusammengesetzten Primärschlüssel haben.
maple_shaft
5

Einige Anforderungen sind in Ihrer Frage nicht klar. Die richtige Antwort hängt davon ab, was Ihr Kunde wünscht. Wenn ich Sie wäre, würde ich den Kunden danach fragen:

0-Was ist der Unterschied zwischen einem Benutzer und einem Mitarbeiter?

1-Angenommen, ein Mitarbeiter = Benutzer, was ist, wenn ein Mitarbeiter die Abteilungen wechselt?

2-Kann eine Gruppe von Mitarbeitern 1 Anfrage stellen?

3-Kann ein Mitarbeiter mehreren Abteilungen angehören? Was ist mit dem CEO?

4-Gibt es eine Untergruppe von Mitarbeitern, die Anfragen stellen dürfen?

5-Was passiert mit der Anfrage, wenn ein Mitarbeiterdatensatz gelöscht wird (falls überhaupt)?

6-Könnten Sie eine Anfrage löschen? Was passiert, wenn die Anfrage nicht beantwortet wird? (Stellen Sie sicher, dass Sie den Mitarbeiterdatensatz von RI nicht löschen.)

7-Kann der Mitarbeiter die "gleiche" Anfrage mehr als einmal stellen (definieren Sie die "gleiche")

8-Wie gehe ich mit Anfragen für Mitarbeiter um, wenn sie das Unternehmen verlassen (storniere ihre Anfragen oder lösche die Anfragen?)

Es mag weitere Fragen geben, aber ich möchte betonen, dass die Lösung von den genauen Anforderungen und dem Projektumfang abhängt . Sobald dies bestimmt ist, kann das Schema direkt abgeleitet werden. Dementsprechend können beide vorgestellten Lösungen korrekt sein.

Keine Chance
quelle
+1 Dies sind wichtige Fragen, die geklärt werden müssen, bevor ein solches Schema entworfen werden kann. Ich mag deinen logischen Fluss.
@ Surfer513: ich freue mich über deinen netten kommentar.
NoChance
1

Ich möchte ein paar Punkte in Form von Notizen hinzufügen, die explizit auf einige der potenziellen Vorteile der Verwendung einer Join-Tabelle hinweisen, wie es Ihr hochbezahlter Berater getan hat.

  • Bei korrekter Indizierung (z. B. wenn UserDepartmentTable die beiden Fremdschlüssel indiziert) tritt bei einer solchen Join-Tabelle nur ein geringer Leistungsverlust auf, da die Fremdschlüssel nicht eindeutig sind. Wenn die Fremdschlüssel garantiert eindeutig sind, ist das Nachschlagen nach der mir bekannten kleinen Datenbanktheorie UserDepartmentTable.Departmentnicht "schwieriger" als das Nachschlagen einer anderen Spalte in der UserTabelle.
  • Mit der Verknüpfungstabelle können Sie flexibler andere Informationen zur Zuordnung zwischen Benutzer und Abteilung einrichten (z. B. Zeitstempel bei der Erstellung).
  • Mit der Verknüpfungstabelle können Sie die Zuordnung relativ einfach "versionieren" (z. B. wenn ein Benutzer die Abteilungen wechselt, ein boolesches Index-Flag auslösen UserDepartmentTable.Active, das "false" lautet, und eine neue Zuordnung erstellen, die aktiv ist). Es ist auch möglich, eine Versionierung der Abteilungszuordnung mit dem Zweitabellenmodell (nur Benutzer und Abteilung) durchzuführen, dies ist jedoch schwieriger und erfordert das Hinzufügen mindestens einer weiteren Spalte oder das Ausführen von Datenbankakrobatik, um das Duplizieren von Primärschlüsseln zu vermeiden.
  • Damit können Sie ganz einfach Eins-zu-Viele oder Viele-zu-Eins oder Viele-zu-Viele-Assoziationen zuweisen.

Davon abgesehen gibt es mehrere Gründe, NICHT das zu tun, was Ihr hochbezahlter Berater getan hat.

  • Alle oben genannten Vorteile berücksichtigen mögliche zukünftige Bedürfnisse und erschweren die Dinge für den heutigen Tag. Es ist nicht YAGNI-konform. Das Schreiben einer Migration, die von Ihrem Zwei-Tabellen-Modell zu einem Join-Tabellen-Modell wechselt, ist später nur noch schwer möglich. Sie können dies tun, wenn sich die geschäftlichen Anforderungen ändern. Es kann verwirrend sein, es vorher zu tun.
  • Das verwirrt andere Entwickler. Ja, ich würde zwar sagen, dass die Erwartung eines Webentwicklers Ihrer Größe (bei dem Sie die Entscheidungen der Berater überprüfen) darin besteht, eine Join-Tabelle zu verstehen und zu erkennen, sie ist jedoch immer noch komplizierter als nötig und angesichts der fehlenden geschäftlichen Anforderungen. es verursacht Verwirrung.
Steven
quelle
nette analyse - allerdings würde ich nicht sagen, dass ich als dev in meinem tagesjob eine statur habe, außer dass ich der einzige hier bin, der etwas über db / c # / vb / etc weiß ... also denke, ich bin ein teil davon Zeit dev standardmäßig. Dies ist ein ziemlich kleines Projekt, so dass die Berater schiere Anzahl von Tabellen und Verknüpfungen ließ mich sagen "wtf" (aber dank Ihnen feine Leute sage ich jetzt "oic ...")
Jim
Ein ziemlich altes Thema, aber immer noch relevant ... Refactoring kann sehr schwierig sein. Stellen Sie sich vor, Sie benötigen zukünftig mehrere Abteilungen anstatt einer, aber Sie haben nur eine Abteilungs-ID in Benutzer als FK. Sie werden wahrscheinlich doppelte Verweise (Users.DeptID und UsersDepartmentsTable) oder vollständigen Müll haben, wie durch Kommas getrennte Listen in Users.DeptID oder XML. Die richtige Lösung könnte nicht einfach hinzugefügt werden, wie von YAGNI oder KISS vorgeschlagen, würde jedoch behindert.
Erik Hart
0

Ohne die vollständige Struktur der benötigten Informationen kann ich nicht sagen, ob es schrecklich ist oder nicht. Zumindest das abgebildete Stück ist jedoch nicht von "WTF" -Design. Es scheint nur als 3. Normalform der Datenstruktur (na ja, wir haben theoretisch auch 4. und 5. auch)

Einige Gespräche können Platz für UserDepartmentTable zwischen zwei Schulen von "natürlichen" und "künstlichen" Schlüsseln im gezeigten Stück haben. Nichts mehr, wie ich sehen kann

Normalisierung ist aus vielen Gründen die Regel eines guten DB-Entwicklers / Designers. * De * Normalisierungen werden manchmal während der Entwicklung verwendet, um die Geschwindigkeit zu steigern

Fauler Dachs
quelle