Tabella degli ordini e-commerce. Salvare i prezzi o utilizzare una tabella di controllo / cronologia?


13

Sto progettando il mio primo schema di eCommerce. Sto leggendo l'argomento da un po 'di tempo, e sono un po' confuso riguardo al rapporto tra an order_line_iteme aproduct

A productpuò essere acquistato. Ha vari dettagli, ma il più importante è unit_price.

An order_line_itemha una chiave esterna per l' product_idacquisto, l' quantityacquisto e unit_priceil momento in cui il cliente ha acquistato il prodotto.

La maggior parte di ciò che ho letto afferma che l' unit_priceon the order_line_itemdovrebbe essere esplicitamente aggiunto (cioè non referenziato attraverso il product_id). Ha senso, poiché il negozio potrebbe cambiare il prezzo in futuro, il che rovinerebbe i rapporti sugli ordini, il monitoraggio, l'integrità ecc.

La cosa che non capisco, è perché salvare direttamente il unit_pricevalore in order_line_item?

Non sarebbe meglio creare una tabella di audit / cronologia che documenti la unit_pricemodifica di un product?

Quando order_line_itemviene creato un, product_auditviene aggiunta la chiave esterna della tabella e il prezzo può essere recuperato (per riferimento) da lì.

Mi sembra che ci siano molti aspetti positivi nell'utilizzare questo approccio (meno duplicazione dei dati, cronologia delle variazioni di prezzo, ecc.), Quindi perché non viene usato più frequentemente? Non ho trovato un esempio di uno schema di eCommerce che utilizza questo approccio, mi sto perdendo qualcosa?

UDPATE: Sembra che la mia domanda si riferisca alla dimensione che cambia lentamente . Sono ancora confuso, poiché la dimensione a modifica lenta si riferisce al data warehouse e agli OLAP. Quindi i tipi di dimensione a modifica lenta possono essere applicati al mio database di processo delle transazioni commerciali (OLTP)? Mi chiedo se sto mescolando molti concetti, apprezzerei molto un po 'di guida.


In realtà farei entrambe le cose: memorizzare il prezzo di vendita nella riga ordine e memorizzare una cronologia dei prezzi dei prodotti. Perché entrambi hanno scopi diversi. La memorizzazione del prezzo di vendita renderà le richieste sugli ordini molto più semplici e veloci. D'altra parte potresti voler recuperare i vecchi prezzi anche per i prodotti che non sono stati venduti.
a_horse_with_no_name

Sicuramente rendere più semplici le richieste di ordini non può essere l'unico driver dietro il risparmio del prezzo finale ogni volta. Dopotutto è un database relazionale - le query non sarebbero così difficili.
Gaz_Edge

3
Memorizzare il prezzo di vendita nella riga ordine non è "non relazionale" (e lo considero normalizzato così come i prezzi di vendita sono un attributo diretto della riga ordine secondo me). L'arte di usare un database relazionale riguarda la conoscenza dei limiti. Se gestisci un negozio con 100 prodotti e 5 ordini al giorno, la memorizzazione e il recupero di vecchi prezzi non è un problema. Se stai gestendo un mercato con milioni di prodotti, migliaia di rivenditori e centinaia di ordini al minuto, fare una query su quella cronologia sarà un problema.
a_horse_with_no_name

Dove vorresti conservare i prezzi storici? Da quello che sto leggendo avrei bisogno di due database. Uno per OLTP uno per OLAP. La storia va nell'OLAP?
Gaz_Edge,

Risposte:


10

Come hai identificato, la memorizzazione del prezzo nell'ordine semplifica l'implementazione tecnica. Ci sono una serie di ragioni commerciali per cui questo può essere utile però.

Oltre alle transazioni Web, molte aziende supportano le vendite attraverso altri canali, ad esempio:

  • Per telefono
  • Agenti di vendita "on the road"
  • In un luogo fisico (ad es. Negozio, ufficio)

In questi casi, l'ordine può essere inserito nel sistema qualche tempo dopo la transazione. In queste circostanze può essere difficile identificare correttamente quale record di prezzo storico dovrebbe essere utilizzato: la memorizzazione del prezzo unitario direttamente sull'ordine è l'unica opzione possibile.

Più canali spesso rappresentano un'altra sfida: prezzi diversi per lo stesso prodotto. I supplementi per gli ordini telefonici sono comuni e alcuni clienti possono negoziare uno sconto. Potresti essere in grado di rappresentare tutti i prezzi possibili per tutti i canali nello schema del tuo prodotto, ma incorporarlo nelle tabelle degli ordini può diventare (molto) complesso.

Ovunque sia consentita la negoziazione, diventa molto difficile collegare la cronologia dei prezzi al prezzo dell'ordine concordato (a meno che gli agenti non abbiano limiti di negoziazione molto stretti). È necessario memorizzare il prezzo sull'ordine stesso.

Anche se supporti solo le transazioni web e hai una struttura dei prezzi relativamente semplice, c'è ancora un problema interessante da superare: come gestire gli aumenti di prezzo nelle transazioni di volo? L'azienda insiste sul fatto che il cliente debba pagare aumenti o onorare il prezzo originale (quando il prodotto è stato aggiunto al carrello)? Se è quest'ultima l'implementazione tecnica è complicata: devi trovare un modo per assicurarti di mantenere correttamente la versione dei prezzi nella sessione.

Infine, molte aziende stanno iniziando a utilizzare prezzi altamente dinamici. Potrebbe non esserci un prezzo fisso per un determinato prodotto: viene sempre calcolato in fase di esecuzione in base a fattori quali l'ora del giorno, la domanda del prodotto e così via. In questi casi, il prezzo non può in primo luogo essere confrontato con il prodotto!


3

Aggiungerò alcuni punti pratici che ho visto.

  1. I prodotti sono transitori.

    Ciò che potrebbero significare oggi, potrebbe non essere lo stesso di quello che hanno usato per indicare un anno fa. Lo stesso codice sku (e quindi il product_id), potrebbe riferirsi a diverse varianti / tipi di prodotto in diverse fasi.

    Non tutti comprendono tutte le preoccupazioni a portata di mano; quindi un utente può cambiare gli attributi del prodotto originale invece di crearne uno nuovo per sua ignoranza. Molte volte, questo potrebbe accadere a causa del piano su cui un utente sta lavorando (Ehi! Posso avere solo 100 sku, quindi perché non continuare a cambiare quelli più vecchi invece di aggiornare il piano) Quindi, vedi, in molti carrelli , un prodotto non significherà mai la stessa cosa per sempre.

  2. Prezzi diversi in base alle condizioni di ordinazione e spedizione

    Come menzionato dall'utente @Chris, prezzi diversi potrebbero essere applicabili in diversi scenari.

    Nella maggior parte dei carrelli, vengono memorizzati almeno 3 campi diversi: il prezzo unitario, l'importo dello sconto e il prezzo scontato. In quelli più avanzati, troverai altri 2 - prezzo unitario con tasse, prezzo scontato con tasse. Potresti trovare un paio di campi in più per descrivere i costi del metodo di spedizione e i costi del metodo di pagamento aggiuntivi. Le percentuali di imposta possono variare a seconda dello stato, del prodotto, del paese, del metodo di spedizione e così via, così come gli altri costi. Allo stesso modo gli sconti possono variare a seconda della geografia, delle promozioni, dei tempi di vendita e così via. Quindi, ci sono informazioni che possono essere ottenute solo a livello di ordine e queste informazioni combinate non possono essere generate dai dati nella sola tabella dei prodotti.

  3. Separazione degli interessi

    Molti carrelli sono implementati in un modo, in modo che diversi team possano avere il controllo su diverse parti di dati. Qualcuno che gestisce il sistema degli ordini non ha sempre bisogno di sapere quali sono tutti i prodotti in magazzino, quali erano i prezzi in un determinato momento, quali sono le alternative per un determinato sku e così via. Conservare i dati relativi al prodotto insieme ai dati dell'ordine aiuta a separare le preoccupazioni. Ciò potrebbe valere anche nelle fasi di sviluppo, se team diversi gestiscono parti diverse del sistema.

  4. Scalabilità più semplice su più sistemi

    Molte volte, il sistema di gestione degli ordini, il motore delle regole, il motore del catalogo, il sistema di gestione dei contenuti sono tutti costruiti / gestiti come sistemi separati. Ciò consente di ottimizzare le varie condizioni di carico e generare informazioni specialistiche specifiche per ciascun sistema. Un sistema, quindi, non può essere ritenuto di riscatto a causa della non disponibilità di informazioni da un altro sistema.

  5. Sviluppo e tempo di esecuzione più rapidi

    Ho usato il termine "tempo di sviluppo" qui, sebbene l'uso di "tempo di debug" sarebbe più appropriato. Ogni volta che si verifica un nuovo sviluppo, sarà più veloce se i dati necessari saranno disponibili senza aggiungere complessità, poiché in tal modo ci saranno cicli di debug relativamente più piccoli.

    Immagina che ti sia stato chiesto di generare rapporti su richiesta per gli sconti offerti su base giornaliera per un determinato mese di sei mesi. Se hai il prezzo originale, il prezzo scontato in 1-2 tabelle insieme all'ordine, ordina i dettagli dell'articolo, questo è praticamente semplice. Se tuttavia, devi andare a recuperare i prezzi da un'altra tabella, quindi gli sconti applicabili da un'altra tabella e quindi capire i dettagli, sia il tempo di sviluppo che quello di esecuzione saranno più alti.

Un buon design dovrebbe cercare di ottimizzare tanto per il futuro, come dovrebbe per il presente.


2

Potrebbe finire per costare di più in deposito, ma preferisco includere tutti i dettagli rilevanti della vendita con la transazione stessa, in modo che se per qualsiasi motivo la nostra pista di controllo viene rotta o un amministratore ignora le sicurezze in atto, i dettagli del vendita come: valuta utilizzata, prezzo unitario, quantità, tasse applicate e il valore che hanno raggiunto, ecc. sono tutti disponibili. Generalmente lo conservo come XML in modo che possa essere flessibile da una vendita all'altra.


EDIT: Per espandere ciò che stavo dicendo brevemente sopra, nel mio commento di follow-up di seguito, e ciò che @a_horse_with_no_name ha toccato sopra, la ridondanza nei dati di transazione non è solo importante, ma è anche necessaria su larga scala.

Suppongo che tu stia sviluppando usando OOP e quindi dovresti probabilmente avere un oggetto transazione e un oggetto prodotto che comprende tutto e / o un oggetto prezzo. Nella mia esperienza personale, preferisco essere prolisso nella mia storia, la conservazione è relativamente economica.

Quello che abbiamo fatto è creare una cronologia degli oggetti che puoi facilitare utilizzando un RDBMS esistente o un po 'di archivio dei valori chiave NOSQL (o ancora meglio un RDBMS che consente connessioni NoSQL come handlersocket o memcache) e memorizziamo la cronologia degli oggetti in questo modo, con ogni dettaglio e variazione di prezzo in un posto facilmente e rapidamente disponibili. Se sei serio, potresti persino usare DIFF per risparmiare sulla memoria e archiviare solo le modifiche in avanti, anche se ha i suoi avvertimenti. Ciò dovrebbe occuparsi della tua cronologia e il vantaggio degli oggetti serializzati è che il tuo sistema sarà / dovrebbe essere in grado di ripristinarli come gli oggetti in cui sono stati memorizzati. Questo si prende cura della storia.

Per quanto riguarda il mio suggerimento, archiviare i dettagli della transazione come tasse, valuta, ecc. Con la transazione stessa significa che non è necessario cercare altrove tali dettagli, l'oggetto della transazione sarà a conoscenza delle sue proprietà e le visualizzazioni potranno occuparsi di presentare i dati variabili come meglio credi. Ottieni un rapido accesso all'istantanea e hai l'ulteriore vantaggio di registrazioni ridondanti e verificabili.

Ne vale la pena, fidati di me!


non ha molto senso dire che non lo usi perché potrebbe essere eliminato. È possibile ignorare qualsiasi dato. Qualsiasi strategia dovrebbe mantenere i backup
Gaz_Edge

@Gaz_Edge Non si escludono a vicenda, è comunque possibile utilizzare una pista di controllo e archiviare i dettagli con le transazioni, la ridondanza in questo caso è giustificata. Non lasciarti mai con questi dati importanti per un singolo punto di errore. Nel nostro caso, utilizzo un archivio oggetti centralizzato come meccanismo di cronologia anziché cercare di creare una cronologia per tipo di oggetto (come una transazione o un prodotto in questo caso). Avrò sia l'intero oggetto della transazione nella storia, ma tutti i dettagli più importanti con il record stesso. Questo è interamente a parte degli oggetti prodotto nella storia.
oucil,

e se volessi eseguire rapporti sugli ordini? Ti piace quanti prodotti x sono stati acquistati? O quanti ordini superiori all'importo y? Salvare come XML significa perdere la possibilità di interrogare i dati, a meno che non mi sbagli
Gaz_Edge,

@Gaz_Edge Non è vero, se stai parlando di MySQL, hai SELECT ExtractValue(field_name, '/x/path/');così che potresti filtrare per cose come, tutte le transazioni in una valuta specifica, o tutte le transazioni con un determinato valore fiscale minimo o altro. Rapporti su larga scala possono essere fatti dalla cronologia degli oggetti. Per rapporti su larga scala è possibile configurare un elasticsearchserver / un'istanza con rapporti in stile BigData che si ridimensiona facilmente in milioni di documenti +.
oucil,

@Gaz_Edge Dovrei anche menzionare, i report di cui stai parlando (acquisti su valore, vendite di prodotti, ecc.) Sono report comuni e quelli dovrebbero avere valori memorizzati come valori colonnari con il record delle transazioni per un'elaborazione più rapida. Tutto ciò che è importante ma non necessariamente riportato spesso può andare nell'XML. I dati dell'istantanea sono in realtà solo per due cose, 1. il problema Dimensione a modifica lenta e 2. Convalida e confronto quando un cliente si lamenta e devi vedere rapidamente chi ha ragione. Non è per l'uso quotidiano.
oucil,

1

Il mio voto sarebbe quello di memorizzare il prezzo unitario sull'elemento pubblicitario e tenere traccia della cronologia dei prezzi dei tuoi prodotti in una tabella separata. La mia giustificazione per questo è per una maggiore flessibilità.

Anche se la tua struttura dei prezzi è rigida e ben definita e non consente le variazioni sopra menzionate da @Chris Saxon, ti senti a tuo agio che sarà sempre così? Anche se sei sicuro, perché dipingiti in un angolo? Penso che sarebbe una buona idea archiviarlo nei dettagli dell'elemento pubblicitario perché non riesco a pensare a un motivo convincente per tenerlo separato.

Per quanto riguarda la memorizzazione della cronologia dei prezzi, esiste un valore definito nel memorizzarla separatamente in quanto potrebbero esserci variazioni nel prezzo di un articolo e nessuno lo ha acquistato. Sarebbe sicuramente un'informazione utile per sapere se una variazione di prezzo era inefficace. Come accennato, si tratta di un caso d'uso classico di una dimensione a modifica lenta di tipo 2 in uno scenario di data warehouse. In genere, qualsiasi modifica del prezzo nella tabella del prodotto viene acquisita e una nuova riga viene aggiunta alla tabella delle dimensioni con il prezzo aggiornato e un timestamp per indicare quando è avvenuta la modifica. La riga precedente avrebbe la data di fine aggiornata per indicare che non è più il prezzo effettivo. Quindi un approccio sarebbe quello di tracciare questo tipo di cambiamento in un data warehouse.

Tuttavia, se non si desidera occuparsi della progettazione di uno schema di data warehouse e di un processo ETL contemporaneamente alla progettazione del database e-commerce OLTP, questa cronologia potrebbe sicuramente essere acquisita nel nostro database e-commerce. Questo potrebbe essere fatto come descritto con la creazione di una tabella product_audit separata che pende dalla tabella del prodotto e contiene le date di inizio e fine per quando quella versione di un prodotto era in vigore. Potrebbe anche essere fatto nella tabella del prodotto stesso aggiungendo le date di inizio e fine alla tabella per indicare quale prodotto è attualmente attivo. Tuttavia, a seconda del numero di prodotti e del numero o delle modifiche dei prezzi a cui è soggetta la tua azienda, ciò potrebbe rendere la tabella dei prodotti molto più ampia del previsto e causare problemi di prestazioni delle query in un secondo momento.

Infine, separare la cronologia dei prezzi dal prezzo unitario effettivo sull'elemento pubblicitario potrebbe sicuramente dare alcune altre opportunità analitiche per vedere quando un prodotto è stato venduto ad un prezzo che era al di sopra o al di sotto del prezzo elencato al momento.


Grazie per la risposta. Penso che la strategia con cui sto andando sarà quella di progettare l'OLTP per il libro. In realtà mi piace l'idea di avere un data warehouse per i report. Sebbene aggiunga del lavoro aggiuntivo (creazione di un nuovo schema), lo schema può essere personalizzato su OLAP. In un certo senso evito uno scenario in cui sto cercando di inserire una spina quadrata in un foro circolare.
Gaz_Edge,

@Gaz_Edge: mi trovo in una situazione simile in termini di decisione per il mio nuovo progetto. Potete per favore interessarvi di condividere le vostre opinioni su quale approccio progettuale avete adottato un anno fa? Ha funzionato bene?
Coder Absolute,

@CoderAbsolute la mia soluzione originale era molto orientata al "database". La mia applicazione è ora incentrata su un'architettura orientata al servizio. Ora ho molti piccoli schemi di database disaccoppiati piuttosto che uno strettamente accoppiato. La necessità di 3N attraverso uno schema enorme è ormai scomparsa. Quindi ora aggiungo il prezzo unitario direttamente all'ordine. Mantenere le variazioni storiche dei prezzi dei prodotti è ormai svanito in quanto non era un requisito aziendale. Spero possa aiutare.
Gaz_Edge,

0

Concordo pienamente con l'idea primaria di mantenere insieme le informazioni relative all'ordine (contesto). Solo una piccola nota a margine che una tale situazione si presenterà solo quando si sta progettando la propria applicazione in modo molto incentrato sul database e tutto ruota attorno al grande db grasso. Se cambi il tuo punto di vista guardando il dominio del problema da una diversa angolazione, noterai chiaramente che l'ordine è un'istantanea acquisita di un evento molto speciale nel ciclo di vita della tua applicazione. Quando si gestiscono i problemi in base al contesto, i problemi del database diventeranno secondari e la complessità di cui tutti hanno paura riguardo alle query e alla creazione di report verrà gestita senza problemi nel modello di dominio.


Alcuni piccoli esempi renderebbero la tua risposta molto più facile da capire. Soprattutto frasi come "L'ordine è un'istantanea acquisita di un evento molto speciale nel ciclo di vita della tua applicazione".
Dezso,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.