Ich arbeite an der Aktualisierung der Produktdatenbank unserer Website. Es ist in MySQL integriert, aber dies ist eher eine allgemeine Frage zum Datenbankdesignmuster.
Ich plane, zu einem Supertype / Subtype-Muster zu wechseln. Unsere aktuelle / vorherige Datenbank besteht hauptsächlich aus einer einzelnen Tabelle, die Daten zu einem einzelnen Produkttyp enthält. Wir möchten unser Produktangebot um unterschiedliche Produkte erweitern.
Dieser neue Entwurfsentwurf ist wie folgt:
Product product_[type] product_attribute_[name]
---------------- ---------------- ----------------------------
part_number (PK) part_number (FK) attributeId (PK)
UPC specific_attr1 (FK) attribute_name
price specific_attr2 (FK)
... ...
Ich habe eine Frage zu den Produktattributtabellen. Die Idee hier ist, dass ein Produkt eine Liste gegebener Attribute wie Farbe haben kann: Rot, Grün, Blau oder Material: Kunststoff, Holz, Chrom, Aluminium usw.
Diese Liste wird in einer Tabelle gespeichert und der Primärschlüssel (PK) für dieses Attributelement wird in der spezifischen Produkttabelle als Fremdschlüssel (FK) verwendet.
(Martin Fowlers Buch Patterns of Enterprise Application Architecture nennt dies " Foreign Key Mapping ")
Auf diese Weise kann eine Website-Oberfläche die Liste der Attribute für einen bestimmten Attributtyp abrufen und in einem Dropdown-Auswahlmenü oder einem anderen UI-Element ausspucken. Diese Liste kann als "autorisierte" Liste von Attributwerten betrachtet werden.
Die Anzahl der Verknüpfungen, die beim Ziehen eines bestimmten Produkts auftreten, erscheint mir zu hoch. Sie müssen jede Produktattributtabelle mit dem Produkt verknüpfen, damit Sie die Felder dieses Attributs abrufen können. Normalerweise ist dieses Feld einfach nichts anderes als eine Zeichenfolge (varchar) für seinen Namen.
Dieses Entwurfsmuster erstellt eine große Anzahl von Tabellen, und Sie erhalten eine Tabelle für jedes Attribut. Eine Idee, dem entgegenzuwirken, wäre, für alle Produktattribute eher eine „Grab-Bag“ -Tabelle zu erstellen. Etwas wie das:
product_attribute
----------------
attributeId (PK)
name
field_name
Auf diese Weise könnte Ihr Tisch folgendermaßen aussehen:
1 red color
2 blue color
3 chrome material
4 plastic material
5 yellow color
6 x-large size
Dies könnte dazu beitragen, das Kriechen von Tabellen zu verringern, verringert jedoch nicht die Anzahl der Verknüpfungen und es fühlt sich ein wenig falsch an, so viele verschiedene Typen in einer einzigen Tabelle zu kombinieren. Sie können jedoch ganz einfach alle verfügbaren Farbattribute abrufen.
Möglicherweise gibt es jedoch ein Attribut, das mehr Felder als nur "Name" enthält, z. B. den RGB-Wert einer Farbe. Dies würde erfordern, dass dieses bestimmte Attribut möglicherweise eine andere Tabelle oder ein einzelnes Feld für das Name: Wert-Paar hat (was seine eigenen Nachteile hat).
Das letzte Entwurfsmuster, an das ich denken kann, ist das Speichern des tatsächlichen Attributwerts in der spezifischen Produkttabelle und überhaupt keine „Attributtabelle“. Etwas wie das:
Product product_[type]
---------------- ----------------
part_number (PK) part_number (FK)
UPC specific_attr1
price specific_attr2
... ...
Anstelle eines Fremdschlüssels für eine andere Tabelle würde er den tatsächlichen Wert enthalten, z.
part_number color material
----------- ----- --------
1234 red plastic
Dies würde Verknüpfungen eliminieren und ein Kriechen der Tabelle verhindern (vielleicht?). Dies verhindert jedoch, dass eine „autorisierte Liste“ von Attributen vorhanden ist. Sie können alle aktuell eingegebenen Werte für ein bestimmtes Feld (dh Farbe) zurückgeben, dies beseitigt jedoch auch die Idee, eine „autorisierte Liste“ von Werten für ein bestimmtes Attribut zu haben.
Um diese Liste zu haben, müssten Sie immer noch eine Attributtabelle "Grab Bag" erstellen oder für jedes Attribut mehrere Tabellen (Table Creep) haben.
Dies schafft den größeren Nachteil (und warum ich diesen Ansatz noch nie verwendet habe), den Produktnamen jetzt an mehreren Stellen zu haben.
Wenn Sie den Farbwert "rot" in der Tabelle "Hauptattribut" haben und ihn auch in der Tabelle "Produkt_ [Typ]" speichern, führt eine Aktualisierung der Tabelle "Master" zu einem potenziellen Datenintegritätsproblem, wenn die Anwendung dies nicht tut Aktualisieren Sie nicht alle Datensätze mit dem alten Wert in der Tabelle "product_type".
Nach meiner langwierigen Erklärung und Analyse dieses Szenarios ist mir klar geworden, dass dies kein ungewöhnliches Szenario sein kann und es möglicherweise sogar einen Namen für diese Art von Situation gibt.
Gibt es allgemein akzeptierte Lösungen für diese Designherausforderung? Ist die potenziell große Anzahl von Joins akzeptabel, wenn die Tabellen relativ klein sind? Ist das Speichern des Attributnamens anstelle einer Attribut-PK unter bestimmten Umständen akzeptabel? Gibt es eine andere Lösung, über die ich nicht nachdenke?
Einige Hinweise zu dieser Produktdatenbank / Anwendung:
- Produkte werden nicht häufig aktualisiert / hinzugefügt / entfernt
- Attribute werden nicht häufig aktualisiert / hinzugefügt / entfernt
- Die Tabelle wird am häufigsten zum Lesen / Zurückgeben von Informationen abgefragt
- Das serverseitige Caching ist aktiviert, um das Ergebnis einer bestimmten Abfrage / eines bestimmten Ergebnisses zwischenzuspeichern
- Ich plane, mit nur einem Produkttyp zu beginnen und andere im Laufe der Zeit zu erweitern / hinzuzufügen, und werde möglicherweise mehr als 10 verschiedene Typen haben
quelle
Antworten:
Ich persönlich würde ein Modell verwenden, das dem folgenden ähnlich ist:
Die Produkttabelle wäre ziemlich einfach, Ihre wichtigsten Produktdetails:
Zweitens die Attributtabelle zum Speichern der verschiedenen Attribute.
Erstellen Sie schließlich die Tabelle product_attribute als JOIN-Tabelle zwischen jedem Produkt und den damit verbundenen Attributen.
Je nachdem, wie Sie die Daten verwenden möchten, sehen Sie sich zwei Verknüpfungen an:
Siehe SQL Fiddle mit Demo . Dies gibt Daten im Format zurück:
Wenn Sie die Daten jedoch in einem
PIVOT
Format zurückgeben möchten, in dem Sie eine Zeile mit allen Attributen als Spalten haben, können SieCASE
Anweisungen mit einem Aggregat verwenden:Siehe SQL Fiddle mit Demo . Die Daten werden im folgenden Format zurückgegeben:
Wie Sie sehen, haben die Daten möglicherweise ein besseres Format für Sie. Wenn Sie jedoch eine unbekannte Anzahl von Attributen haben, werden sie aufgrund hartcodierter Attributnamen leicht unhaltbar. In MySQL können Sie vorbereitete Anweisungen verwenden, um dynamische Pivots zu erstellen . Ihr Code wäre wie folgt (siehe SQL Fiddle With Demo ):
Dies führt zum gleichen Ergebnis wie die zweite Version, ohne dass ein Hardcode erforderlich ist. Obwohl es viele Möglichkeiten gibt, dies zu modellieren, denke ich, dass dieses Datenbankdesign das flexibelste ist.
quelle
Ich würde Taryns Antwort erweitern und die Attributtabelle so ändern, dass sie die Spalte fk_attribute_type_id enthält , die anstelle der Spalte attribute_name steht und auf die neue Tabelle attribute_type verweist.
Sie haben also Attributtypen in einer Tabelle strukturiert und können diese jederzeit an einer Stelle ändern.
Meiner Meinung nach ist es besser, mit "dial" zu arbeiten (Tabelle mit möglichen Typen) als mit enum type (wie in der Spalte attribute_name (und obendrein ist es eigentlich nicht name, sein Attributtyp)).
quelle