2009-09-18 3 views
15

Ho un numero di oggetti diversi con un numero variabile di attributi. Fino ad ora ho salvato i dati in file XML che consentono facilmente un numero di attributi in continuo cambiamento. Ma sto cercando di spostarlo in un database.Come memorizzare i dati con il numero dinamico di attributi in un database

Quale sarebbe il modo preferito per memorizzare questi dati?

Poche strategie ho identificato finora:

  • Avere un unico campo denominato "attributi" nella tabella dell'oggetto e memorizzare i dati serializzati o json'ed in là.
  • Memorizzare i dati in due tabelle (oggetti, attributi) e usare un terzo per salvare le relazioni, rendendolo una vera relazione n: m. Soluzione molto pulita, ma probabilmente molto costosa per recuperare un intero oggetto e tutti i suoi attributi
  • Identificazione di attributi di tutti gli oggetti in comune e creazione di campi per questi nella tabella dell'oggetto. Memorizza gli attributi rimanenti come dati serializzati in un altro campo. Questo ha un vantaggio rispetto alla prima strategia, rendendo più facili le ricerche.

Qualche idea?

+0

Qual è la motivazione per passare a una soluzione db? Hai detto di seguito che la velocità è la tua principale preoccupazione. Pensi che una soluzione DB sarebbe più veloce del tuo attuale approccio XML? –

+0

Una quarta strategia mi è venuta in mente con DVK che proponeva lo stesso: Memorizzazione di attributi comuni nella tabella degli oggetti e memorizzazione di tutti gli altri utilizzando una relazione 1: n una seconda tabella. Sembra il miglior compromesso per velocità, flessibilità e soluzione pulita (@Tobiask) –

+0

@Corey, no non lo faccio. La soluzione XML è incredibilmente veloce al momento e non credo che un DB possa tenere il passo con questo. È più un esercizio per il mio, cercando di rendere il sistema più flessibile per quanto riguarda le opzioni di archiviazione e allo stesso tempo migliorare le mie competenze MySQL. –

risposta

18

Se mai piano per la ricerca di attribtes specifici, è una cattiva idea serializzali in una singola colonna, dal momento che dovrai usare le funzioni per riga per ottenere le informazioni - questo non è mai scalabile.

opterei per la seconda scelta. Avere un elenco di attributi in una tabella di attributi, gli oggetti nella propria tabella e una tabella di relazioni molti-a-molti denominata attributi dell'oggetto.

Ad esempio:

objects: 
    object_id integer 
    object_name varchar(20) 
    primary key (object_id) 
attributes: 
    attr_id  integer 
    attr_name varchar(20) 
    primary key (attr_id) 
object_attributes: 
    object_id integer references (objects.object_id) 
    attr_id  integer references (attributes.attr_id) 
    primary key (object_id,attr_id) 

la sua preoccupazione per le prestazioni si nota, ma, nella mia esperienza, è sempre più costoso di dividere una colonna che per combinare più colonne. Se si scopre che ci sono problemi di prestazioni, è perfettamente accettabile interrompere 3NF per motivi di prestazioni.

In tal caso, lo memorizzerei allo stesso modo ma ho anche una colonna con i dati serializzati grezzi. Se si utilizzano trigger di inserimento/aggiornamento per mantenere sincronizzati i dati colonnare e combinati, non si avranno problemi. Ma non dovresti preoccuparti di questo finché non si verifica un problema reale.

Utilizzando tali trigger, si riduce a icona il lavoro richiesto solo quando i dati cambiano. Cercando di estrarre le informazioni di sottocolonna, si esegue il lavoro non necessario su ogni selezione.

+0

Esattamente la mia preoccupazione per la prima strategia. –

+0

la domanda è quale è meglio per le prestazioni il tuo metodo è eav quale è la tua opinione sulla modellazione di JSON che memorizza i dati –

+0

@babakfaghihian, penso che lo copro nei miei ultimi due paragrafi, sì? Va bene rompere 3NF per le prestazioni a condizione di comprendere e mitigare i rischi (degli elementi di dati "in disaccordo" tra loro). Memorizzare i dati originali (XML, JSON o qualsiasi altra cosa) è un approccio a questo. – paxdiablo

1

sembra che tu abbia bisogno di qualcosa leccare couchdb, non un RDBMS.

+0

Sembra una soluzione ideale. Sfortunatamente mi occupo principalmente di scenari in cui non ho la possibilità di utilizzare molto oltre MySQL, per non parlare dell'installazione di un altro DB sul server. –

6

Una variazione sulla vostra soluzione 2D si trova a soli due tavoli (assumendo tutti gli attributi sono di un solo tipo):

T1: | colonne di dati Object | object_id |

T2: | ID oggetto | nome_attributo | valore attributo | (indice univoco sulle prime 2 colonne)

Questo è ancora più efficiente se combinato con la terza soluzione, ad es. tutti i campi comuni vanno in T1.

Sstuffing> 1 Abilità nella stessa blob non è raccomandato - non è possibile filtrare per attributi, non è possibile aggiornare in modo efficiente le

+0

In realtà, è esattamente quello che mi è venuto in mente dopo aver letto di nuovo le mie tre strategie. Sembra il modo migliore per andare. –

+1

Ciao. Questa è chiamata tabella Entity-Atribute-Value, ed è cattiva progettazione http://programmers.stackexchange.com/questions/93124/eav-is-it-really-bad-in-all-scenarios –

+0

@GabriBotha - le risposte alla domanda collegata non supportano in alcun modo la tua affermazione piatta e non finanziata che si tratta di un design "cattivo". È un design con difetti specifici, come TUTTI i design, e situazioni specifiche in cui è l'approccio migliore. – DVK

1

se si desidera modificare/manipolare/eliminare gli attributi in un secondo momento, fare una vera n: m (seconda opzione) sarà quella per cui vado. (Oppure prova a renderlo 2 la tabella in cui lo stesso attributo si ripete.Ma la dimensione dei dati sarà alta)

Se non hai a che fare con gli attributi (solo acquisendo e mostrando i dati), puoi andare avanti e memorizzare in un campo con qualche separatore (assicurarsi che il separatore non si verifichi nel valore dell'attributo)

1

Se si utilizza un db relazionale, penso che abbia fatto un buon lavoro elencando le opzioni. Ognuno ha i suoi pro e contro. Sei nella posizione migliore per decidere cosa funziona meglio per le tue circostanze.

L'approccio serializzato è probabilmente il più veloce (a seconda del codice per la deserializzazione), ma significa che non sarà possibile interrogare i dati con SQL. Se dici che non hai bisogno di interrogare i dati con SQL, allora sono d'accordo con @longneck, forse dovresti usare uno stile chiave/valore db invece di un db relazionale.

MODIFICA - leggendo più dei vostri commenti, PERCHÉ state passando a un db se la velocità è la vostra preoccupazione principale. Cosa c'è di male nella tua attuale implementazione XML?

2

ho usato per implementare this scheme:

t_class (id RAW(16), parent RAW(16)) -- holds class hierachy. 
t_property (class RAW(16), property VARCHAR) -- holds class members. 
t_declaration (id RAW(16), class RAW(16)) -- hold GUIDs and types of all class instances 
t_instance (id RAW(16), class RAW(16), property VARCHAR2(100), textvalue VARCHAR2(200), intvalue INT, doublevalue DOUBLE, datevalue DATE) -- holds 'common' properties 

t_class1 (id RAW(16), amount DOUBLE, source RAW(16), destination RAW(16)) -- holds 'fast' properties for class1. 
t_class2 (id RAW(16), comment VARCHAR2(200)) -- holds 'fast' properties for class2 
--- etc. 

RAW(16) è dove Oracle tiene GUID s

Se si desidera selezionare tutte le proprietà di un oggetto, si esegue:

SELECT i.* 
FROM (
     SELECT id 
     FROM t_class 
     START WITH 
       id = (SELECT class FROM t_declaration WHERE id = :object_id) 
     CONNECT BY 
       parent = PRIOR id 
     ) c 
JOIN property p 
ON  p.class = c.id 
LEFT JOIN 
     t_instance i 
ON  i.id = :object_id 
     AND i.class = p.class 
     AND i.property = p.property 

t_property trattieni cose che normalmente non cerchi (come descrizioni di testi, ecc.)

Le proprietà veloci sono in realtà le normali tabelle presenti nel database, per rendere efficienti le query. Tengono valori solo per le istanze di una determinata classe o dei suoi discendenti. Questo per evitare ulteriori join.

Non è necessario utilizzare tabelle veloci e limitare tutti i dati a queste quattro tabelle.

+1

Wow, questo è anche un passo avanti. Ma non porterebbe a un gran numero di tabelle se ne hai una per ogni tipo di classe? E la tua ultima istruzione SQL mi fa davvero sperare che il libro MySQL che ho ordinato arrivi prima o poi .. –

+1

'@ Jörg': questo era in' Oracle' e questa è la sintassi 'Oracle'. In 'MySQL', dovrai implementare questa funzione in un altro modo: http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/ – Quassnoi

+0

È necessario creare tabelle solo per" proprietà veloci ": quando è necessario creare un indice composito su due o più proprietà. Altrimenti, puoi avere solo tabelle di base '4'. – Quassnoi

3

Lasciatemi dare un po 'di concretezza a ciò che stava dicendo DVK.

valori Assumendo sono dello stesso tipo della tabella sarà simile (buona fortuna, mi sento si sta andando ad avere bisogno di esso):

 
dynamic_attribute_table 
------------------------ 
id   NUMBER 
key  VARCHAR 
value  SOMETYPE? 

esempio (auto):

 
|id| key | value | 
--------------------------- 
| 1|'Make' |'Ford'  | 
| 1|'Model' |'Edge'  | 
| 1|'Color' |'Blue'  | 
| 2|'Make' |'Chevrolet'| 
| 2|'Model' |'Malibu' | 
| 2|'MaxSpeed'|'110mph' | 

Così ,
entità 1 = {('Marca', 'Ford'), ('Modello', 'Bordo'), ('Colore', 'Blu')}
e,
entità 2 = {('Make ',' Chevrolet '), (' Modello ',' Malibu '), (' MaxSpeed ​​',' 110 mph ')}.

+0

cosa succede se vuoi dire che una macchina ha colore nero e colore giallo? –