Database valore attributo entità vs. e-commerce rigoroso modello relazionale


136

È sicuro affermare che il modello di database EAV / CR è errato. Detto ciò,

Domanda: quale modello di database, tecnica o modello dovrebbe essere utilizzato per gestire "classi" di attributi che descrivono prodotti di e-commerce che possono essere modificati in fase di esecuzione?

In un buon database di e-commerce, memorizzerai classi di opzioni (come la risoluzione TV, quindi hai una risoluzione per ogni TV, ma il prodotto successivo potrebbe non essere un televisore e non avere "Risoluzione TV"). Come li memorizzi, esegui ricerche in modo efficiente e consenti ai tuoi utenti di impostare tipi di prodotto con campi variabili che descrivono i loro prodotti? Se il motore di ricerca rileva che i clienti in genere cercano TV in base alla profondità della console, è possibile aggiungere la profondità della console ai campi, quindi aggiungere una singola profondità per ciascun tipo di prodotto TV in fase di esecuzione.

C'è una bella caratteristica comune tra le buone app di e-commerce in cui mostrano una serie di prodotti, quindi hanno menu laterali "drill down" in cui è possibile vedere "Risoluzione TV" come intestazione e le prime cinque risoluzioni TV più comuni per il trovato insieme. Fai clic su uno e mostra solo i televisori di quella risoluzione, permettendoti di approfondire ulteriormente selezionando altre categorie nel menu laterale. Queste opzioni sarebbero gli attributi dinamici del prodotto aggiunti in fase di esecuzione.

Ulteriori discussioni:

Per farla breve, ci sono collegamenti su Internet o descrizioni di modelli che potrebbero "accademicamente" risolvere la seguente configurazione? Ringrazio Noel Kennedy per aver suggerito una tabella delle categorie, ma la necessità potrebbe essere maggiore. Lo descrivo in un modo diverso di seguito, cercando di evidenziarne il significato. Potrei aver bisogno di una correzione del punto di vista per risolvere il problema, oppure potrei dover approfondire l'EAV / CR.

Adoro la risposta positiva al modello EAV / CR. I miei colleghi sviluppatori dicono tutti ciò che Jeffrey Kemp ha toccato di seguito: "le nuove entità devono essere modellate e progettate da un professionista" (tolto dal contesto, leggi la sua risposta di seguito). Il problema è:

  • le entità aggiungono e rimuovono gli attributi settimanalmente
    (le parole chiave di ricerca determinano gli attributi futuri)
  • le nuove entità arrivano settimanalmente
    (i prodotti vengono assemblati dalle parti)
  • le vecchie entità vanno via settimanalmente
    (archiviate, meno popolari, stagionali)

Il cliente desidera aggiungere attributi ai prodotti per due motivi:

  • dipartimento / ricerca per parole chiave / tabella comparativa tra prodotti simili
  • configurazione del prodotto di consumo prima del pagamento

Gli attributi devono avere un significato, non solo una ricerca per parole chiave. Se vogliono confrontare tutte le torte che hanno una "glassa di panna montata", possono fare clic sulle torte, fare clic sul tema del compleanno, fare clic su glassa di panna montata, quindi controllare tutte le torte che sono interessanti sapendo che hanno tutte la glassa di panna montata. Questo non è specifico per le torte, solo un esempio.


Perché non puoi semplicemente avere una tabella 'categoria' con una chiave esterna che fa riferimento a se stessa?
Noel Kennedy,

29
Non è sicuro, né preciso, affermare che il modello di database EAV è errato, poiché è adatto per alcune applicazioni.
spencer7593,

Cosa succede se si decorano vari oggetti con varie proprietà, ereditando da un genitore come in Entity Framework 4? Come persiste quegli oggetti?
Zachary Scott,

1
Sono appena tornato a sottolineare questo eccellente articolo sull'esperienza di un consulente con un sistema basato su una versione estrema di EAV. Leggilo! simple-talk.com/opinion/opinion-pieces/bad-carma
Jeffrey Kemp

1
EAV è un modello di database molto praticabile. Sto lavorando a un problema simile come te e la soluzione è EAV. Consiglierei il seguente articolo: sqlblog.com/blogs/aaron_bertrand/archive/2009/11/19/…
Sandor,

Risposte:


75

Ci sono alcuni pro e contro generali a cui riesco a pensare, ci sono situazioni in cui una è migliore dell'altra:

Opzione 1, modello EAV:

  • Pro: meno tempo per progettare e sviluppare una semplice applicazione
  • Pro: nuove entità facili da aggiungere (potrebbero anche essere aggiunte dagli utenti?)
  • Pro: componenti di interfaccia "generici"
  • Contro: codice complesso richiesto per convalidare tipi di dati semplici
  • Contro: SQL molto più complesso per report semplici
  • Contro: rapporti complessi possono diventare quasi impossibili
  • Contro: scarse prestazioni per grandi set di dati

Opzione 2, Modellazione di ciascuna entità separatamente:

  • Contro: richiede più tempo per raccogliere requisiti e design
  • Contro: le nuove entità devono essere modellate e progettate da un professionista
  • Contro: componenti dell'interfaccia personalizzata per ogni entità
  • Pro: vincoli e convalida del tipo di dati semplici da implementare
  • Pro: SQL è facile da scrivere, facile da capire ed eseguire il debug
  • Pro: anche i report più complessi sono relativamente semplici
  • Pro: migliori prestazioni per grandi set di dati

Opzione 3, combinazione (entità modello "correttamente", ma aggiungere "estensioni" per gli attributi personalizzati per alcune / tutte le entità)

  • Pro / Con: più tempo necessario per raccogliere requisiti e design dell'opzione 1 ma forse non tanto quanto l'opzione 2 *
  • Contro: le nuove entità devono essere modellate e progettate da un professionista
  • Pro: nuovi attributi potrebbero essere facilmente aggiunti in seguito
  • Contro: codice complesso richiesto per convalidare tipi di dati semplici (per gli attributi personalizzati)
  • Contro: componenti di interfaccia personalizzati ancora richiesti, ma per gli attributi personalizzati possono essere possibili componenti di interfaccia generici
  • Contro: SQL diventa complesso non appena un attributo personalizzato viene incluso in un report
  • Contro: buone prestazioni in generale, a meno che non si inizi a cercare o riportare per gli attributi personalizzati

* Non sono sicuro che l'opzione 3 risparmierebbe necessariamente tempo in fase di progettazione.

Personalmente mi spingerei verso l'opzione 2, ed eviterei l'EAV ove possibile. Tuttavia, per alcuni scenari gli utenti hanno bisogno della flessibilità fornita con EAV; ma questo ha un costo eccezionale.


E se avessi una singola tabella con indici per i valori di testo 1-n, quindi in C # (in ram) mappi ciò che vuoi e ciò di cui hai bisogno. Funzionerebbe ancora come un EAV, ma le "corrispondenze" sarebbero modelli di dominio. Un po 'come una serializzazione, ma è possibile utilizzare le selezioni SQL nei campi di testo indicizzati. Nessuna selezione multipla per record. Tutto il "costo" avviene nella RAM.
Zachary Scott,

1
@Zim, che suona quasi come l'opzione 3. Ogni riga ha 1-n colonne "generiche" in più, e i dati in esse memorizzati vengono interpretati a livello di applicazione. Ottieni il vantaggio in termini di prestazioni di avere tutti i dati per un record in un unico posto. I metadati su quelle colonne devono essere archiviati da qualche parte, tuttavia, ed è qui che il costo si insinua. Certo, possiamo memorizzare nella cache i metadati in ram, ma costa ancora di più che avere il dominio modellato direttamente nel codice dell'applicazione. Sicuramente meglio di un modello EAV completo!
Jeffrey Kemp,

1
+10000 Ottima risposta. Oggi le persone risparmiano sulla progettazione del database e sulla raccolta dei requisiti. Preferirebbero scrivere un centinaio di volte più righe di codice, che impiegano del tempo per realizzare un buon design.
Tulains Córdova,

Non è necessaria una progettazione maggiore per l'opzione relazionale (2) rispetto all'opzione EAV (1) se si fornisce solo la struttura dell'opzione 1. E l'interfaccia relazionale è generica dai metadati che descrivono quella struttura. Questo rimuove tutta l'opzione 2 Contro. Tuttavia hai dimenticato l'unico vero Con: DDL può essere troppo lento nella gestione delle tabelle.
philipxy,

Ciao @philipxy, non ho detto "più design". La ragion d'essere dell'EAV è che (presumibilmente) il progettista del sistema può dedicare meno tempo alla progettazione del modello, lasciando questo lavoro di progettazione agli "utenti" in seguito (questa mancanza di design professionale porta ai contro elencati per l'opzione 1) . Se l'EAV non porta a risparmi per il progettista, ciò aggiunge solo più combustibile al fuoco per aver rifiutato l'EAV fuori mano. Inoltre, non sono d'accordo sul fatto che DDL sia "troppo lento" - poiché dovrebbe essere richiesto solo raramente (ad esempio per correggere errori nel modello o implementare nuove funzionalità), le sue prestazioni dovrebbero essere relativamente poco importanti.
Jeffrey Kemp,

63

È sicuro affermare che il modello di database EAV / CR è errato.

No non lo è. È solo che sono un uso inefficiente dei database relazionali. Un negozio puramente chiave / valore funziona perfettamente con questo modello.

Ora, alla tua vera domanda: come archiviare vari attributi e mantenerli ricercabili?

Usa EAV. Nel tuo caso sarebbe un singolo tavolo extra. indicizzandolo sia sul nome che sul valore dell'attributo, la maggior parte dei RDBM userebbe la compressione del prefisso per ripetere le ripetizioni del nome dell'attributo, rendendolo davvero veloce e compatto.

EAV / CR diventa brutto quando lo usi per sostituire i campi "reali". Come con ogni strumento, l'abuso è "cattivo" e gli dà un'immagine negativa.


quindi la domanda è che ho 15 campi aggiuntivi per una delle mie categorie e nel modello eav richiede 16 join + tabella principale in modo da fare 16 join a sinistra per la ricerca di prodotti (e avere 16 dove se il cliente vuole) in 3-4 milioni di record ( un sito web per la vendita di prodotti di seconda mano da parte di persone), quindi ci vuole un basso livello di perofrmance?
Babak Faghihian,

2
Se questi "campi aggiuntivi" sono già definiti, sarebbe sicuramente meglio come "campi reali". E, naturalmente, fare un numero illimitato di join in una query di grandi dimensioni sarebbe un pesante tributo (ma potrebbe essere ancora ok!). Quello che ho fatto su un progetto ricco di metadati è consentire un numero qualsiasi di "tag" (come record EAV) per "elemento principale", ma la "query di grandi dimensioni" seleziona solo alcuni tagname predefiniti, mantenendo limitato il numero totale di join (attualmente tipica è a soli 4 tag e circa 5 altri join), e quando l'utente seleziona un elemento specifico, allora si fetchs tutto ciò che riguarda, ma per un singolo elemento.
Javier,

ma ovviamente, quel sistema specifico è attualmente portato su un hstorecampo (solo uno dei motivi per cui usiamo PostgreSQL)
Javier,

15
// A questo punto, vorrei prendere un momento per parlarti del formato PSD Magento / Adobe .
// Magento / PSD non è una buona piattaforma / formato di e -commerce . Magento / PSD non è nemmeno una cattiva piattaforma / formato di e -commerce . Chiamarlo tale sarebbe un
// insulti ad altre piattaforme / formati di e -commerce non validi, come Zencart o OsCommerce. No, Magento / PSD è una piattaforma / formato di e -commerce abissale . avere
// ha lavorato su questo codice per diverse settimane, il mio odio per Magento / PSD è cresciuto fino a diventare un incendio
// che brucia con la feroce passione di un milione di soli.

http://code.google.com/p/xee/source/browse/trunk/XeePhotoshopLoader.m?spec=svn28&r=11#107

I modelli interni sono al massimo stravaganti, come se qualcuno mettesse lo schema in un gioco boggle, lo sigillasse e lo mettesse in uno shacker di vernice ...

Mondo reale: sto lavorando a un'app di adempimento midware ed ecco una delle domande per ottenere informazioni sull'indirizzo.

CREATE OR REPLACE VIEW sales_flat_addresses AS
SELECT sales_order_entity.parent_id AS order_id, 
       sales_order_entity.entity_id, 
       CONCAT(CONCAT(UCASE(MID(sales_order_entity_varchar.value,1,1)),MID(sales_order_entity_varchar.value,2)), "Address") as type, 
       GROUP_CONCAT( 
         CONCAT( eav_attribute.attribute_code," ::::: ", sales_order_entity_varchar.value )
         ORDER BY sales_order_entity_varchar.value DESC
         SEPARATOR '!!!!!' 
       ) as data
  FROM sales_order_entity
       INNER JOIN sales_order_entity_varchar ON sales_order_entity_varchar.entity_id = sales_order_entity.entity_id
       INNER JOIN eav_attribute ON eav_attribute.attribute_id = sales_order_entity_varchar.attribute_id
   AND sales_order_entity.entity_type_id =12
 GROUP BY sales_order_entity.entity_id
 ORDER BY eav_attribute.attribute_code = 'address_type'

Esatte informazioni sull'indirizzo per un ordine, pigramente

-

Riepilogo: utilizzare Magento solo se:

  1. Ti vengono dati grandi sacchi di denaro
  2. Devi
  3. Goditi il ​​dolore

Questo è un post più vecchio, ma vorrei averlo trovato 3 mesi fa quando ho avviato un progetto Magento per un cliente. +1 per l'analogia di boggle / shaker!
Trevorc,

1
Abbastanza interessante, Magento sembra essere il re della strada in termini di sistemi di e-commerce. Forse solo il marketing è molto buono
Herr

1
Magento non è popolare a causa del livello di manutenzione, ma della possibilità di personalizzare, consentendo a chiunque di implementare nuove funzionalità senza cambiamenti di architettura o poche modifiche. Questa funzione ha un costo.
Diego Mendes,

Stai lontano da Magento 2 se vuoi evitare Triple Pain e More Pain in cima sia per FE che per BE
TheBlackBenzKid

15

Sono sorpreso che nessuno abbia menzionato i database NoSQL.

Non ho mai praticato NoSQL in un contesto di produzione (ho appena testato MongoDB e ne sono rimasto colpito) ma il punto centrale di NoSQL è riuscire a salvare elementi con attributi diversi nello stesso "documento".


Si consideri che le scritture su MongoDB richiedono il blocco a livello di database e cosa significhi per il traffico di produzione simultaneo.
Bill Karwin,

Considera che la durata del blocco è nell'ordine dei microsecondi.
Ciao World

12

Laddove le prestazioni non sono un requisito fondamentale, come in un tipo di applicazione ETL, EAV ha un altro vantaggio distinto: i risparmi differenziali.

Ho implementato una serie di applicazioni in cui un requisito di over-arching era la capacità di vedere la cronologia di un oggetto di dominio dalla sua prima "versione" al suo stato attuale. Se quell'oggetto dominio ha un gran numero di attributi, ciò significa che ogni modifica richiede l'inserimento di una nuova riga nella tabella corrispondente (non un aggiornamento perché la cronologia andrebbe persa, ma un inserimento). Diciamo che questo oggetto di dominio è una persona e ho 500k persone da tracciare con una media di oltre 100 modifiche nel ciclo di vita delle persone a vari attributi. Abbinalo al fatto che rara è l'applicazione che ha solo 1 oggetto di dominio principale e ti renderai rapidamente conto che le dimensioni del database aumenterebbero rapidamente senza controllo.

Una soluzione semplice consiste nel salvare solo le modifiche differenziali ai principali oggetti di dominio anziché salvare ripetutamente le informazioni ridondanti.

Tutti i modelli cambiano nel tempo per riflettere le nuove esigenze aziendali. Periodo. L'uso di EAV è solo uno degli strumenti nella nostra scatola da usare; ma non dovrebbe mai essere automaticamente classificato come "cattivo".


2
+1 per "L'uso di EAV non è che uno degli strumenti nella nostra casella da utilizzare, ma non dovrebbe mai essere automaticamente classificato come" cattivo "."
Catchops

A proposito, questo si chiama SCD (dimensioni che cambiano lentamente). Anche i requisiti bitemporali (un caso specifico di SCD di tipo 4) richiedono lo schema EAV per gli attributi che hanno questa proprietà. Ricorda, il 99% di NoSQL non ha join nativi, quindi se hai bisogno di join "live" con questo tipo di dati, EAV è l'unica strada da percorrere.
Cowbert,

3

Sto lottando con lo stesso problema. Potrebbe essere interessante consultare la seguente discussione su due soluzioni di e-commerce esistenti: Magento (EAV) e Joomla (struttura relazionale regolare): https://forum.virtuemart.net/index.php?topic=58686.0

Sembra che le prestazioni EAV di Magento siano un vero spettacolo.

Ecco perché sono incline verso una struttura normalizzata. Per ovviare alla mancanza di flessibilità, sto pensando di aggiungere in futuro un dizionario di dati separato (XML o tabelle DB separate) che potrebbe essere modificato e, in base a ciò, il codice dell'applicazione per visualizzare e confrontare le categorie di prodotti con nuovi set di attributi sarebbe generato, insieme a script SQL.

Tale architettura sembra essere lo sweetspot in questo caso - flessibile e performante allo stesso tempo.

Il problema potrebbe essere l'uso frequente di ALTER TABLE in un ambiente live. Sto usando Postgres, quindi il suo MVCC e DDL transazionale allevia il dolore.


2

Continuo a votare per la modellazione al livello atomico più significativo per EAV. Consenti agli standard, alle tecnologie e alle applicazioni che si orientano verso determinate comunità di utenti di decidere modelli di contenuto, esigenze di ripetizione di attributi, grani, ecc.


2

Se si tratta solo degli attributi del catalogo prodotti e quindi i requisiti di convalida per tali attributi sono piuttosto limitati, l'unico vero svantaggio di EAV è il rendimento delle query e anche questo è solo un problema quando la tua query si occupa di più "cose" (prodotti) con attributi, le prestazioni per la query "dammi tutti gli attributi per il prodotto con ID 234" mentre non ottimali sono ancora molto veloci.

Una soluzione consiste nell'utilizzare il modello di database / EAV SQL solo per il lato amministratore / modifica del catalogo prodotti e disporre di un processo che denormalizza i prodotti in qualcosa che lo rende ricercabile. Dato che hai già degli attributi e quindi è piuttosto probabile che tu voglia sfaccettare, questo qualcosa potrebbe essere Solr o ElasticSearch. Questo approccio evita sostanzialmente tutti gli aspetti negativi del modello EAV e la complessità aggiunta è limitata alla serializzazione di un prodotto completo su JSON al momento dell'aggiornamento.


2

EAV ha molti svantaggi:

  1. Degrado delle prestazioni nel tempo Una volta che la quantità di dati nell'applicazione aumenta oltre una certa dimensione, è probabile che il recupero e la manipolazione di tali dati diventino sempre meno efficienti.
  2. Le query SQL sono molto complesse e difficili da scrivere.
  3. Problemi di integrità dei dati. Non è possibile definire chiavi esterne per tutti i campi necessari.
  4. Devi definire e mantenere i tuoi metadati.

1. Questo vale anche per la maggior parte dei database relazionali; ecco perché è stato inventato lo sharding. 2. La modellizzazione dei dati può essere complessa e difficile da implementare. Ho trascorso settimane e mesi in attesa di modifiche allo schema del cubo OLAP. 3. Già in gran parte già fatto nel software ora 4. È necessario farlo "in ERwin, Excel e Visio" quando si modella comunque uno schema relazionale.
Cowbert,

1

Ho un problema leggermente diverso: invece di molti attributi con valori sparsi (che è forse una buona ragione per usare EAV), voglio archiviare qualcosa di più simile a un foglio di calcolo. Le colonne nel foglio possono cambiare, ma all'interno di un foglio tutte le celle conterranno dati (non sparsi).

Ho fatto un piccolo set di test per confrontare due progetti: uno usando EAV e l'altro usando un ARRAY Postgres per memorizzare i dati delle celle.

EAV inserisci qui la descrizione dell'immagine

Vettore inserisci qui la descrizione dell'immagine

Entrambi gli schemi hanno indici su colonne appropriate e gli indici vengono utilizzati dal pianificatore.

Si è scoperto che lo schema basato su array era un ordine di grandezza più veloce sia per gli inserti che per le query. Da test rapidi, sembrava che entrambi si ridimensionassero linearmente. I test non sono molto accurati, però. Suggerimenti e forcelle sono benvenuti: hanno una licenza MIT.


come hai fatto i join sulle colonne del foglio (ad es. vlookup) con il modello di array? Non è necessario scrivere la propria funzione di tipo merge array? Sicuramente può essere buono come l'ordinamento di unione precompilato se hai usato sheet_id + coordinata x + coordinata y di una cella come chiave del valore della cella. (per emulare Excel, pregenerare una tabella di ricerca per coordinate X dove 0-18278 sono colonne A-ZZZ (Excel massimo a 16384)), quindi è possibile selezionare i valori in cui sheet_id = uuid e x-coord = 0 e y-coord <1001 per ottenere le prime 1000 file di col A.
Cowbert,

@cowbert hai ragione; in realtà carico solo le colonne che mi interessano e faccio il join in Python. Slack!
z0r,
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.