Ich entwerfe mein erstes E-Commerce-Schema. Ich habe ein wenig über das Thema gelesen und bin etwas verwirrt über die Beziehung zwischen a order_line_item
und aproduct
A product
kann gekauft werden. Es hat verschiedene Details, aber das Wichtigste ist unit_price
.
An order_line_item
hat einen Fremdschlüssel zu dem product_id
gekauften, dem quantity
gekauften und dem unit_price
zu dem Zeitpunkt, an dem der Kunde das Produkt gekauft hat.
Das meiste, was ich gelesen habe, besagt, dass das unit_price
On order_line_item
explizit hinzugefügt werden sollte (dh nicht durch das referenziert wird product_id
). Sinnvoll, da das Geschäft den Preis in Zukunft ändern könnte, was Bestellberichte, Nachverfolgung, Integrität usw. durcheinander bringen würde.
Was ich nicht verstehe, ist, warum ich den unit_price
Wert direkt in das speichere order_line_item
.
Wäre es nicht besser, eine Audit- / Verlaufstabelle zu erstellen, die die unit_price
Änderung von a dokumentiert product
?
Beim Erstellen von order_line_item
wird der Fremdschlüssel der product_audit
Tabelle hinzugefügt, und der Preis kann von dort (als Referenz) abgerufen werden.
Es scheint mir, dass die Verwendung dieses Ansatzes eine Menge Vorteile mit sich bringt (weniger Duplizierung von Daten, Verlauf von Preisänderungen usw.). Warum wird er also nicht häufiger verwendet? Ich habe noch kein Beispiel für ein E-Commerce-Schema gefunden, das diesen Ansatz verwendet. Fehlt mir etwas?
UDPATE: Meine Frage scheint sich auf die sich langsam ändernde Dimension zu beziehen . Ich bin jedoch immer noch verwirrt, da sich Slowly Changing Dimension auf Data Warehouse und OLAPs bezieht. Können langsam wechselnde Dimensionstypen auf meine OLTP-Datenbank (Main Business Transaction Process Database) angewendet werden? Ich frage mich, ob ich viele Konzepte vermische. Würde mich sehr über eine Anleitung freuen.
quelle
Antworten:
Wie Sie festgestellt haben, erleichtert das Speichern des Preises in der Bestellung die technische Implementierung. Es gibt jedoch eine Reihe von geschäftlichen Gründen, warum dies von Vorteil sein kann.
Zusätzlich zu Web-Transaktionen unterstützen viele Unternehmen den Vertrieb über andere Kanäle, z.
In diesen Fällen kann die Bestellung zu einem bestimmten Zeitpunkt nach dem Abschluss der Transaktion in das System eingegeben werden. Unter diesen Umständen kann es schwierig bis unmöglich sein, den zu verwendenden historischen Preisdatensatz korrekt zu identifizieren. Die Speicherung des Stückpreises direkt auf der Bestellung ist die einzig mögliche Option.
Mehrere Kanäle bringen oft eine andere Herausforderung mit sich - unterschiedliche Preise für dasselbe Produkt. Zuschläge für telefonische Bestellungen sind üblich - und einige Kunden können sich selbst einen Rabatt aushandeln. Möglicherweise können Sie alle möglichen Preise für alle Kanäle in Ihrem Produktschema darstellen, die Einbeziehung in Ihre Auftragstabellen kann jedoch (sehr) komplex werden.
Überall dort, wo diese Verhandlung erlaubt ist, wird es sehr schwierig, den Preisverlauf mit dem vereinbarten Auftragspreis zu verknüpfen (es sei denn, die Vermittler haben sehr enge Verhandlungsgrenzen). Sie müssen den Preis auf der Bestellung selbst speichern.
Auch wenn Sie nur Web-Transaktionen unterstützen und eine relativ einfache Preisstruktur haben, bleibt ein interessantes Problem zu überwinden - wie sollten Preiserhöhungen bei Flugtransaktionen behandelt werden? Besteht das Unternehmen darauf, dass der Kunde Erhöhungen zahlen muss, oder wird der ursprüngliche Preis eingehalten (als das Produkt in den Warenkorb gelegt wurde)? Wenn es das letztere ist, ist die technische Implementierung kompliziert - Sie müssen einen Weg finden, um sicherzustellen, dass Sie die Preisversion in der Sitzung korrekt pflegen.
Schließlich beginnen viele Unternehmen, hochdynamische Preise zu verwenden. Möglicherweise gibt es keinen festen Preis für ein bestimmtes Produkt - er wird zur Laufzeit immer auf der Grundlage von Faktoren wie Tageszeit, Nachfrage nach dem Produkt usw. berechnet. In diesen Fällen darf der Preis erst gar nicht gegen das Produkt gespeichert werden!
quelle
Ich werde einige praktische Punkte hinzufügen, die ich gesehen habe.
Produkte sind vergänglich.
Was sie heute bedeuten, ist vielleicht nicht dasselbe wie vor einem Jahr. Derselbe SKU-Code (und daher die product_id) kann sich auf verschiedene Varianten / Arten des Produkts in verschiedenen Phasen beziehen.
Nicht jeder versteht alle anstehenden Bedenken; Daher kann ein Benutzer die Attribute des Originalprodukts ändern, anstatt aus eigener Unwissenheit ein neues zu erstellen. Häufig kann dies passieren, weil ein Benutzer einen Plan hat (Hey! Ich kann nur 100 Skus haben, also warum nicht die älteren ändern, anstatt den Plan zu aktualisieren). Also, sehen Sie, in vielen Karren , ein Produkt wird niemals für immer dasselbe bedeuten.
Abweichende Preise je nach Bestell- und Versandbedingungen
Wie der Benutzer @Chris bereits erwähnt hat, können in verschiedenen Szenarien unterschiedliche Preise gelten.
In den meisten Warenkörben werden mindestens 3 verschiedene Felder gespeichert - der Stückpreis, der Rabattbetrag und der Rabattpreis. In fortgeschritteneren Versionen finden Sie 2 weitere - Stückpreis mit Steuern, reduzierter Preis mit Steuern. Möglicherweise finden Sie in einigen weiteren Feldern eine Beschreibung der Versandart- und zusätzlichen Zahlungsartgebühren. Die Steuersätze können je nach Bundesstaat, Produkt, Land, Versandart usw. variieren, ebenso wie die anderen Kosten. In ähnlicher Weise können die Rabatte je nach Region, Werbeaktionen, Verkaufszeit und so weiter variieren. Daher gibt es Informationen, die nur auf Auftragsebene abgerufen werden können, und diese kombinierten Informationen können nicht allein aus Daten in der Produkttabelle generiert werden.
Trennung von Bedenken
Viele Carts sind so implementiert, dass verschiedene Teams die Kontrolle über verschiedene Teile von Daten haben können. Jemand, der das Bestellsystem verwaltet, muss nicht immer wissen, welche Produkte auf Lager sind, welche Preise zu unterschiedlichen Zeitpunkten verfügbar waren, welche Alternativen für einen bestimmten Artikel verfügbar sind und so weiter. Wenn produktbezogene Daten zusammen mit den Bestelldaten aufbewahrt werden, wird eine Trennung der Bedenken erreicht. Dies kann auch in Entwicklungsphasen der Fall sein, wenn verschiedene Teams verschiedene Teile des Systems verwalten.
Einfachere Skalierbarkeit über mehrere Systeme hinweg
Häufig werden das Auftragsverwaltungssystem, die Regel-Engine, die Katalog-Engine und das Inhaltsverwaltungssystem als separate Systeme erstellt / verwaltet. Dies hilft bei der Optimierung für verschiedene Lastzustände und bei der Erzeugung spezieller Informationen für jedes System. Ein System kann daher nicht als Lösegeld eingestuft werden, da Informationen von einem anderen System nicht verfügbar sind.
Schnellere Entwicklung und Laufzeit
Ich habe hier den Begriff "Entwicklungszeit" verwendet, obwohl die Verwendung von "Debugging-Zeit" geeigneter wäre. Immer wenn eine neue Entwicklung stattfindet, ist es schneller, wenn die benötigten Daten verfügbar sind, ohne dass die eigene Komplexität erhöht wird, da dann vergleichsweise kürzere Debug-Zyklen auftreten.
Stellen Sie sich vor, Sie wurden gebeten, On-Demand-Berichte für Rabatte zu erstellen, die für einen bestimmten Monat vor einem halben Jahr täglich angeboten werden. Wenn Sie den ursprünglichen Preis haben, den ermäßigten Preis in 1-2 Tabellen zusammen mit der Bestellung, Bestellartikeldetails, ist dies so ziemlich unkompliziert. Wenn Sie jedoch Preise von einem anderen Tisch und dann die entsprechenden Rabatte von einem anderen Tisch abrufen und dann die Details herausfinden müssen, sind sowohl die Entwicklung als auch die Laufzeit höher.
Ein gutes Design sollte versuchen, sowohl für die Zukunft als auch für die Gegenwart zu optimieren.
quelle
Es kostet möglicherweise mehr Speicherplatz, aber ich ziehe es vor, alle relevanten Details des Verkaufs mit der Transaktion selbst zu verknüpfen, sodass die Details der Transaktion überschrieben werden, wenn aus irgendeinem Grund unser Prüfpfad unterbrochen wird oder ein Administrator die vorhandenen Sicherheitsvorkehrungen außer Kraft setzt Verkauf wie: verwendete Währung, Stückpreis, Menge, angewendete Steuern und welcher Wert sie erreichten, usw. sind alle verfügbar. Ich speichere das im Allgemeinen als XML, damit es von Verkauf zu Verkauf flexibel sein kann.
BEARBEITEN: Um zu erweitern, was ich oben kurz gesagt habe, in meinem nachfolgenden Kommentar und was @a_horse_with_no_name oben angesprochen hat, ist Redundanz in Transaktionsdaten nicht nur wichtig, sondern auch in der Größenordnung notwendig.
Ich gehe davon aus, dass Sie mit OOP aufbauen und daher wahrscheinlich ein Transaktionsobjekt und entweder ein alles umfassendes Produktobjekt und / oder ein Preisobjekt haben sollten. Nach meiner persönlichen Erfahrung bevorzuge ich es, in meiner Geschichte ausführlich zu sein, die Aufbewahrung ist relativ billig.
Wir haben ein Objektprotokoll erstellt, das Sie mithilfe Ihres vorhandenen RDBMS oder einer Variante des NOSQL-Schlüsselwertspeichers (oder besser eines RDBMS, das NoSQL-ähnliche Verbindungen wie Handlersocket oder Memcache ermöglicht) vereinfachen können, und wir speichern das Objektprotokoll Auf diese Weise sind alle Details und Preisänderungen an einem Ort einfach und schnell verfügbar. Wenn Sie es ernst meinen, können Sie sogar DIFFs verwenden, um Speicherplatz zu sparen und die Änderungen nur vorwärts zu speichern, obwohl es seine eigenen Einschränkungen hat. Das sollte sich um Ihren Verlauf kümmern, und der Vorteil serialisierter Objekte besteht darin, dass Ihr System in der Lage sein wird / sollte, sie als die Objekte wiederherzustellen, in denen sie gespeichert wurden. Das kümmert sich um die Geschichte.
In Bezug auf meinen Vorschlag bedeutet das Speichern der Transaktionsdetails wie Steuern, Währung usw. mit der Transaktion selbst, dass Sie nicht anderswo nach diesen Details suchen müssen. Ihr Transaktionsobjekt kennt seine Eigenschaften und Ihre Ansichten können sich um die Präsentation kümmern die variierenden Daten, wie Sie es für richtig halten. Sie erhalten schnellen Zugriff auf den Schnappschuss und profitieren zusätzlich von redundanten und überprüfbaren Aufzeichnungen.
Es lohnt sich, vertrau mir!
quelle
SELECT ExtractValue(field_name, '/x/path/');
nach Dingen wie, allen Transaktionen in einer bestimmten Währung oder allen Transaktionen mit einem bestimmten Mindeststeuerwert oder was auch immer filtern. Berichte in größerem Maßstab können aus der Objekthistorie erstellt werden. Für Berichte in größerem Maßstab können Sie einenelasticsearch
Server / eine Instanz einrichten, der / die Berichte im BigData-Stil erstellt und sich problemlos in mehrere Millionen Dokumente + skalieren lässt.Meine Stimme wäre, den Stückpreis in Ihrer Werbebuchung zu speichern und den Preisverlauf Ihrer Produkte in einer separaten Tabelle zu verfolgen. Meine Rechtfertigung dafür ist zusätzliche Flexibilität.
Auch wenn Ihre Preisstruktur starr und klar definiert ist und die oben erwähnten Variationen von @Chris Saxon nicht zulässt, können Sie sich sicher sein, dass dies immer so sein wird? Auch wenn Sie zuversichtlich sind, warum malen Sie sich in einer Ecke? Ich halte es für eine gute Idee, diese Informationen in der Werbebuchung zu speichern, da mir kein zwingender Grund einfällt, sie getrennt zu halten.
Was das Speichern Ihres Preisverlaufs angeht, so ist es durchaus sinnvoll, diesen separat zu speichern, da sich der Preis eines Artikels ändern kann und niemand ihn gekauft hat. Das wäre auf jeden Fall eine nützliche Information, wenn eine Preisänderung unwirksam wäre. Wie Sie bereits erwähnt haben, handelt es sich hierbei um einen klassischen Anwendungsfall einer sich langsam ändernden Dimension des Typs 2 in einem Data-Warehouse-Szenario. In der Regel wird jede Preisänderung in Ihrer Produkttabelle erfasst, und der Dimensionstabelle wird eine neue Zeile mit dem aktualisierten Preis und einem Zeitstempel hinzugefügt, der angibt, wann diese Änderung stattgefunden hat. In der vorherigen Zeile wird das Enddatum aktualisiert, um anzuzeigen, dass es sich nicht mehr um den effektiven Preis handelt. Ein Ansatz wäre also, diese Art von Änderung in einem Data Warehouse zu verfolgen.
Wenn Sie sich jedoch nicht gleichzeitig mit dem Entwerfen Ihrer OLTP-E-Commerce-Datenbank mit dem Entwerfen eines Data-Warehouse-Schemas und eines ETL-Prozesses befassen möchten, kann dieser Verlauf durchaus in unserer E-Commerce-Datenbank erfasst werden. Dies könnte geschehen, wie Sie es beschrieben haben, indem Sie eine separate product_audit-Tabelle erstellen, die von der product-Tabelle abhängt und Start- und Enddaten für die Gültigkeit dieser Version eines Produkts enthält. Sie können dies auch in der Produkttabelle selbst tun, indem Sie der Tabelle Start- und Enddaten hinzufügen, um anzugeben, welches Produkt gerade aktiv ist. Abhängig von der Anzahl der Produkte und der Anzahl oder Preisänderungen, die Ihr Unternehmen durchläuft, kann dies jedoch dazu führen, dass Ihre Produkttabelle viel größer als beabsichtigt ist und später Probleme mit der Abfrageleistung auftreten.
Wenn Sie Ihren Preisverlauf vom tatsächlichen Stückpreis auf der Werbebuchung trennen, können Sie auf jeden Fall andere Analysemöglichkeiten nutzen, um festzustellen, wann ein Produkt zu einem Preis verkauft wurde, der zu diesem Zeitpunkt über oder unter dem angegebenen Preis lag.
quelle
Ich stimme voll und ganz der Grundidee zu, auftragsbezogene Informationen (Kontext) zusammenzuhalten. Nur eine kleine Randnotiz, dass eine solche Situation nur dann auftritt, wenn Sie Ihre Anwendung sehr datenbankorientiert gestalten und sich alles um die große fette Datenbank dreht. Wenn Sie Ihre Sichtweise ändern, indem Sie die Problemdomäne aus einem anderen Blickwinkel betrachten, werden Sie deutlich feststellen, dass die Reihenfolge eine Momentaufnahme eines ganz besonderen Ereignisses im Lebenszyklus Ihrer Anwendung ist. Wenn Sie Probleme basierend auf dem Kontext behandeln, werden Datenbankprobleme zweitrangig und die Komplexität, vor der jeder Angst hat, Fragen zu stellen und Berichte zu erstellen, wird nahtlos im Domänenmodell behandelt.
quelle