Bevorzugen Sie die Normalisierung der Datenbank gegenüber der Transparenz des Schemas?


10

Eine neue Anforderung ist auf einer alten Codebasis aufgetaucht, die im Grunde eine direkte (interne) Kommunikation zwischen zwei zuvor nicht direkt verwandten Benutzerklassen ermöglicht (die in verschiedenen Tabellen mit völlig unterschiedlichen Schemata gespeichert sind, und leider ist der Code kaum OO-fähig, viel weniger entworfen, daher gibt es keine Elternklasse). Da wir eine Tasche an dieses alte Setup hängen möchten, das diese Funktionalität nie in Betracht gezogen hat, gibt es keine Garantie dafür, dass es keine PK-Kollisionen gibt - angesichts des verwendeten Datensatzes ist praktisch garantiert, dass es diese gibt.

Die Lösung scheint also offensichtlich: Töte es mit Feuer und schreibe das ganze Chaos neu. Eine Mapping-Tabelle. Ich habe zwei Anweisungen für die möglichen Implementierungsmethoden der Karte erhalten, bin jedoch kein DBA. Daher bin ich mir nicht sicher, ob ich Vor- und Nachteile verpasst habe.

Betrachten Sie zur Verdeutlichung der Abstraktion drei Gruppen unterschiedlicher Benutzerdaten: Professoren, Verwaltung, Studenten (Nein, dies ist keine Hausaufgabe. Versprechen!)

Zuordnung 1

(professor_id, admin_id und student_id sind Fremdschlüssel für ihre jeweiligen Tabellen)

| mailing_id (KEY) | professor_id | admin_id | student_id | 
-------------------------------------------------------
| 1001             |     NULL     |    87    |  NULL      |
| 1002             |     123      |   NULL   |  NULL      |
| 1003             |     NULL     |   NULL   |  123       |

Die +/- zu diesem Ansatz scheinen ziemlich nachteilig zu sein:

  • Zwei "verschwendete" Felder pro Zeile
  • Verstößt gegen 2NF
  • Anfällig für das Einfügen / Aktualisieren von Anomalien (eine Zeile mit nur 0-1 Feldsatz NULL, z.

Die Profis sind jedoch nicht ohne eigene Verdienste:

  • Das Mapping kann mit einer einzigen Suche durchgeführt werden
  • Bestimmen Sie einfach die "Quell" -Daten für einen bestimmten Benutzer aus der Mailing-ID

Um ehrlich zu sein, in meinem Bauch mag ich diese Idee überhaupt nicht.

Zuordnung 2

(Angenommen, MSG_ * sind definierte Konstanten, Aufzählungstypen oder ein anderer geeigneter Bezeichner.)

| mailing_id (KEY)  | user_type (UNIQUE1) | internal_id (UNIQUE2)| 
------------------------------------------------------------------
| 1001              | MSG_ADMIN          | 87                    |
| 1002              | MSG_PROF           | 123                   |
| 1003              | MSG_STUDENT        | 123                   |

Mit diesem Setup und einem eindeutigen zusammengesetzten Index von {user_type, internal_id} werden die Dinge viel sauberer, 3NF wird beibehalten und der Anwendungscode muss nicht nach E / A-Anomalien suchen.

Auf der anderen Seite gibt es einen gewissen Transparenzverlust bei der Bestimmung der Benutzerquellentabellen, die außerhalb der Datenbank verarbeitet werden müssen. Dies entspricht im Wesentlichen einer Zuordnung von Werten für den Benutzertyp zu Tabellen auf Anwendungsebene. Im Moment neige ich (ziemlich stark) zu dieser zweiten Abbildung, da der Nachteil eher gering ist.

ABER ich bin mir meiner eigenen Grenzen schmerzlich bewusst und bin mir sicher, dass ich wahrscheinlich Vorteile oder Stolpersteine ​​in beide Richtungen verpasst habe, also wende ich mich klügeren Gedanken zu als meinen.


2
Vielleicht finden Sie Martin Fowlers Ideen zu Rollen eine interessante Lektüre.
Marjan Venema

Es war in der Tat interessant. Leider nicht zu viel Einblick in mein spezifisches Problem
GeminiDomino

Sie werden Professoren bekommen, die Administratoren werden, und Studenten, die Jobs in der Verwaltung bekommen oder sogar 10 Jahre später als Fakultät zurückkehren. Sie haben sie wahrscheinlich schon. Wirst du diese getrennt halten oder versuchen, sie zu vereinen?
Elin

Die Rollen sind nur Beispiele, aber ich verstehe Ihren Standpunkt. In der Praxis würden Benutzer, selbst wenn sie die Rollen wechseln würden, ohnehin als separate Datensätze verbleiben.
GeminiDomino

Wenn wäre großartig, wenn Sie den ersten Absatz neu formulieren würden. Es ist ein bisschen unklar. Ich meine, es ist offensichtlich, dass es ein Problem gibt, aber es ist nicht klar genug, was es ist.
Tulains Córdova

Antworten:


1

Ihre zweite Idee ist die richtige. Mit diesem Ansatz können Sie alle Zuordnungen vornehmen, die Sie zur Integration Ihrer drei kollidierenden Schlüsselbereiche benötigen.

Wichtig ist, dass die Datenbank den größten Teil der Konsistenz, die Sie benötigen, mithilfe deklarativer Einschränkungen auferlegt .

Sie haben bereits mehr Code als Sie möchten. Fügen Sie also nicht mehr Code hinzu, als unbedingt erforderlich ist, um Ihre integrierte Schlüsselliste konsistent zu halten. Lassen Sie Ihr Datenbankmodul das tun, wofür es entwickelt wurde.

Das "Sorgenkind", das Ihnen in Mapping 2 Unbehagen bereitet, ist die USER_TYPESpalte. Diese Spalte ist wichtig, da Sie sie benötigen, um sicherzustellen, dass INTERNAL_IDsie pro Benutzertyp höchstens einmal angezeigt wird. Das einzige Mal, wenn Sie Code benötigen, der überhaupt bekannt USER_TYPEist, ist der Code, der in Ihre Zuordnungstabelle eingefügt und aus dieser gelöscht wird. Dies kann ziemlich gut lokalisiert werden. Ich würde davon ausgehen, dass Sie einen einzelnen Punkt in Ihrem Code erstellen, an dem der Inhalt der Zuordnungstabelle beibehalten wird. Eine zusätzliche Spalte an dieser einen Stelle, an der Daten geschrieben werden, ist keine große Sache. Was Sie wirklich vermeiden möchten, ist das Hinzufügen der zusätzlichen Spalte überall dort, wo die Daten gelesen werden .

Der Code in Ihren Unteranwendungen, der die Zuordnung verwenden muss, kann das USER_TYPEeinfach ignorieren, indem Sie jeder Unteranwendung eine Ansicht geben, die die Zuordnungen auf den einen anwendungsspezifischen Benutzertyp herunterfiltert.


3

Aus Erfahrung empfehle ich, Konsistenz gegenüber Eleganz oder „Best Practice“ zu wählen. Dies entspricht dem vorhandenen Design und DREI Mailing-Tabellen (eine für jede Rolle) mit einer einfachen mailing_id, user_idFeldstruktur.

Es ist unelegant, hat aber einige Vorteile ...

  1. Das Anpassen der vorhandenen Struktur ist für alle anderen Benutzer einfacher, die an diesem Schema arbeiten, bevor es auf die Weide gestellt wird.
  2. Sie haben keine verschwendeten Felder und Sie fordern die Datenbank nicht auf, Dinge abzugleichen, die nicht existieren.
  3. Da jede Tabelle nur miteinander verknüpft ist und es relativ einfach ist, eine Ansicht zu erstellen, in der alle Daten für Ihre Routinen verknüpft sind.

Ich bin sicher, dass viele andere mit diesem Ansatz nicht einverstanden sind, aber das Hauptziel der Normalisierung und der Best Practices besteht darin, den Code konsistenter zu machen, damit er leichter zu befolgen und zu debuggen ist ... und es ist wahrscheinlich nicht möglich, die gesamte Codebasis auf den neuesten Stand zu bringen.


Das Problem bei diesem Ansatz besteht darin, dass die Datenbank dann keine Eindeutigkeit in Mailing-IDs erzwingen kann, was in erster Linie der Hauptzweck der Zuordnung ist: Andernfalls könnte das Koppeln der einzelnen ID-Felder aus jeder Tabelle mit einem Indikator "Benutzertyp" erfolgen ohne Änderung gemacht.
GeminiDomino

Ich verstehe, worauf Sie hinaus wollen, aber nachdem ich an einem solchen System gearbeitet habe, habe ich eine Option angegeben, die Sie möglicherweise nicht in Betracht gezogen haben. Soweit ich es sehe, würde die Mailing-ID einen Inhalt benötigen, auf den irgendwo verwiesen werden kann (was per Post verschickt wurde oder wie das Dokument zu finden ist), sodass die Mailing-ID ohnehin ein Fremdschlüssel sein sollte, was bedeutet, dass Eindeutigkeitsprobleme an anderer Stelle gelöst würden. Während ich es lese, können die mit dem Administrator verknüpften Datentabellen für Studenten und Prof unterschiedliche Strukturen haben, sodass ich nicht sehen kann, dass das Feld Benutzertyp einen Mehrwert bietet. Die ursprünglichen Entwickler müssen dieses Problem gelöst haben. Was haben sie getan?
James Snell

Das Feld "Benutzertyp" würde bestimmen, welche Tabelle diesem bestimmten Datensatz zugeordnet werden soll. Es müsste in beiden Fällen auf Anwendungsebene behandelt werden, und da sie sich in verschiedenen Tabellen befinden, gibt es keine gute Möglichkeit, sie zu einer Fremdschlüsseleinschränkung zu machen. Die ursprünglichen Entwickler scheinen dieses Problem leider überhaupt nicht in Betracht gezogen zu haben, weshalb es sich in ein solches Chaos verwandelt. :)
GeminiDomino
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.