Quando inizi ad arrivare a "campi definiti dall'utente", come spesso si trova nei bug tracker, nella gestione delle risorse dei clienti e in strumenti aziendali simili, è che non sono supportati da una tabella con campi bajillion (se lo sono, è probabile che sia un problema di propria).
Invece quello che trovi sono i disegni della tabella dei valori degli attributi delle entità e lo strumento di amministrazione associato per gestire gli attributi validi.
Considera la seguente tabella:
+ -------------- +
| cosa |
| -------------- |
| id |
| digitare |
| desc |
| attr1 |
| attr2 |
| attr3 |
| attr4 |
| attr5 |
+ -------------- +
Questo è dopo aver aggiunto alcuni attributi. Invece di attr1
far finta che legge artist
o tracks
o genre
o qualunque attributi la cosa ha. E invece di 5, se fosse 50. Chiaramente questo è ingestibile. Richiede anche un aggiornamento del modello e la ridistribuzione dell'applicazione per gestire un nuovo campo. Non ideale
Consideriamo ora la seguente struttura della tabella:
+ -------------- + + --------------- + + ------------- +
| cosa | | thing_attr | | attr |
| -------------- | | --------------- | | ------------- |
| id | <--- + | thing_id (fk) | +> | id |
| digitare | | attr_id (fk) | + - + | nome |
| desc | | valore | | |
+ -------------- + + --------------- + + ------------- +
Hai le tue cose con i suoi campi di base. Hai altri due tavoli. Uno con gli attributi. Ogni campo è una riga nella attr
tabella. E poi c'è il thing_attr
con una coppia di chiavi esterne relative al thing
tavolo e al attr
tavolo. E questo ha quindi un campo valore in cui archiviare qualunque sia il valore del campo per quell'entità.
E ora hai una struttura in cui la tabella attr può essere aggiornata in fase di esecuzione e nuovi campi possono essere aggiunti (o rimossi) al volo senza un impatto significativo sull'applicazione complessiva.
Le query sono un po 'più complesse e anche la convalida diventa più complessa (procedure memorizzate funky o tutto il lato client). È un compromesso nel design.
Considera anche la situazione in cui un giorno devi eseguire una migrazione e torni all'applicazione per scoprire che ora ci sono una mezza dozzina di attributi in più rispetto allo schema che hai distribuito originariamente. Ciò rende possibili brutte migrazioni e aggiornamenti in cui la tabella Valore attributo entità, se utilizzata correttamente, può essere più pulita. (Non sempre, ma può essere.)
Ci sono degli svantaggi nella modifica dello schema in fase di esecuzione? Se l'utente pensa che una cosa abbia bisogno di un nuovo attributo, basta aggiungere dinamicamente una colonna alla tabella?
Se stai lavorando con il sapore appropriato del database nosql, potresti probabilmente farlo (nota che il sapore appropriato del nosql per questo sarebbe probabilmente un archivio di valori-chiave che è, beh, la tabella EAV per quelli relazionali sopra descritti) senza troppi problemi. Tuttavia viene fornito con tutti i compromessi per nosql che sono descritti altrove in grande dettaglio.
Se invece lavori su un database relazionale, devi avere lo schema. L'aggiunta dinamica della colonna significa che alcuni sottoinsieme delle seguenti cose sono vere:
- Stai eseguendo la programmazione di meta-database. Invece di essere in grado di mappare in modo pulito questa colonna su quel campo con un bel ORM, probabilmente stai facendo cose come
select *
e poi facendo un codice complesso per scoprire quali sono effettivamente i dati (vedi ResultSetMetaData di Java ) e quindi archiviarli in una mappa ( o qualche altro tipo di dati - ma non dei bei campi nel codice). Questo quindi getta via un bel po 'di tipo e di errore di battitura che hai con l'approccio tradizionale.
- Probabilmente hai abbandonato l'ORM. Questo significa che stai scrivendo sql grezzo per tutto il codice invece di lasciare che il sistema faccia il lavoro per te.
- Hai rinunciato a fare aggiornamenti puliti. Cosa succede quando il cliente aggiunge un campo con un nome utilizzato anche dalla versione successiva? Nel sito di matchmaking l'upgrade che vuole aggiungere un
hasdate
campo per la memorizzazione di un timestamp è già stato definito come hasdate
con un valore booleano per una partita di successo ... e il tuo upgrade si interrompe.
- Stai fidando che il cliente non rompe il sistema usando una parola riservata che rompe anche le tue domande ... da qualche parte.
- Ti sei limitato a un marchio di database. Il DDL di database diversi è diverso. I tipi di database ne sono l'esempio più semplice.
varchar2
vs text
e simili. Il tuo codice per aggiungere la colonna funzionerebbe su MySQL ma non su Postgres o Oracle o SQL Server.
- Ti fidi che il cliente abbia effettivamente aggiunto bene i dati ? Certo, l'EAV è tutt'altro che ideale ma ora hai alcuni nomi di tabella oscuri orrendi che lo sviluppatore non ha aggiunto, con il tipo di indice errato (se presente), senza vincoli aggiunti nel codice dove è necessario essere e così via.
- Hai assegnato i privilegi di modifica dello schema all'utente che esegue l'applicazione. Little Bobby Drop Tables non è possibile quando si è limitati a SQL piuttosto che a DDL (sicuramente si può fare un
delete * from students
invece, ma non si può davvero rovinare il database in modi sbagliati). Il numero di cose che possono andare storte nell'accesso allo schema a seguito di un incidente o di attività dannose sale alle stelle.
Questo si riduce davvero a "non farlo". Se lo vuoi davvero, scegli uno schema noto della struttura della tabella EAV o un database interamente dedicato a questa struttura. Non permettere alle persone di creare campi arbitrari in una tabella. Il mal di testa non ne vale la pena.