Domanda

Immaginate un modulo web con una serie di caselle di controllo (una o tutte di essi può essere selezionato). Ho scelto di salvarli in una virgola elenco di valori memorizzati in una colonna della tabella di database separato.

Ora, so che la soluzione corretta sarebbe quella di creare un secondo tavolo e correttamente normalizzare il database. E 'stato più veloce per implementare la soluzione facile, e ho voluto avere un proof-of-concept di tale domanda in modo rapido e senza dover spendere troppo tempo su di esso.

ho pensato che il tempo risparmiato e il codice più semplice è valsa la pena nella mia situazione, si tratta di una scelta progettuale difendibile, o dovrei aver normalizzato fin dall'inizio?

Alcuni più contesto, si tratta di una piccola applicazione interna che sostituisce essenzialmente un file di Excel che è stato memorizzato in una cartella condivisa. Inoltre sto chiedendo perché sto pensando di ripulire il programma e renderlo più gestibile. Ci sono alcune cose in là io non sono del tutto soddisfatto, uno di loro è l'argomento di questa domanda.

È stato utile?

Soluzione

Oltre a violare prima forma normale causa del gruppo ripetuto dei valori memorizzati in una singola colonna, elenchi separati da virgole hanno un sacco di altri problemi più pratici:

  • non può garantire che ogni valore è il tipo di dati a destra: non c'è modo di evitare che 1,2,3, banana, 5
  • Non è possibile utilizzare i vincoli di chiave per i valori di collegamento a una tabella di ricerca; non c'è modo di applicare l'integrità referenziale.
  • Non è possibile rispettare l'unicità: non c'è modo di evitare che 1,2,3,3,3,5
  • Non è possibile eliminare un valore dalla lista senza caricare l'intera lista.
  • Non è possibile memorizzare un elenco più lungo di quello che si adatta nella colonna stringa.
  • Hard per la ricerca di tutte le entità con un dato valore nella lista; è necessario utilizzare un inefficiente tavolo-scan. Potrebbe essere necessario ricorrere alle espressioni regolari, per esempio in MySQL:
    idlist REGEXP '[[:<:]]2[[:>:]]' *
  • difficile contare gli elementi nella lista, o fare altre query di aggregazione.
  • Difficile da unire i valori di tabella di ricerca fanno riferimento.
  • Hard per andare a prendere l'elenco in modo ordinato.

Per risolvere questi problemi, è necessario tonnellate di scrittura del codice applicativo, reinventare funzionalità che l'RDBMS fornisce già molto più efficiente .

elenchi separati da virgole sono abbastanza sbagliato che ho fatto questo il primo capitolo nel mio libro: SQL antipattern:. evitando le insidie ??di Programmazione Database

Ci sono momenti in cui è necessario impiegare denormalizzazione, ma come @OMG Ponies menziona , si tratta di casi di eccezione. Eventuali non relazionali “ottimizzazione” benefici un tipo di interrogazione a scapito di altri usi dei dati, in modo da essere sicuri di sapere che le vostre domande devono essere trattati in modo speciale che meritano denormalizzazione.


* MySQL 8.0 non supporta più questa sintassi espressione parola di confine.

Altri suggerimenti

"Una delle ragioni era la pigrizia".

Questo allarme anelli campane. L'unica ragione per cui si dovrebbe fare qualcosa come questo è che si sa come farlo "nel modo giusto", ma si è giunti alla conclusione che c'è un motivo tangibile per non farlo in quel modo.

Detto questo: se i dati che si stanno scegliendo di conservare in questo modo sono dati che non si sarà mai bisogno di query, allora ci può essere un caso per la memorizzazione nel modo che avete scelto

.

(Alcuni utenti metterebbero in discussione l'affermazione nel mio precedente paragrafo, dicendo che "si può mai sapere cosa saranno aggiunti requisiti in futuro". Questi utenti sono o fuorviante o indicando una convinzione religiosa. A volte è vantaggioso per il lavoro a i requisiti avete davanti a voi.)

Ci sono numerose domande sul SO che chiedono:

  • come ottenere un conteggio di valori specifici della virgole lista separato
  • come ottenere i record che hanno solo lo stesso / etc valore 2/3 speciale da parte del virgole lista separato

Un altro problema con l'elenco separato da virgole è garantire i valori sono coerenti - testo memorizzazione intende la possibilità di errori di battitura ...

Questi sono tutti sintomi di dati denormalizzati, ed evidenziare il motivo per cui si dovrebbe sempre modello per dati normalizzati. Denormalizzazione possono essere un'ottimizzazione delle query, da applicare quando la necessità si presenta in realtà .

In generale tutto può essere difendibile se soddisfa i requisiti del progetto. Ciò non significa che la gente d'accordo con o voler difendere la vostra decisione ...

In generale, l'archiviazione dei dati in questo modo non è ottimale (per esempio più difficile da fare query efficienti) e può causare problemi di manutenzione se si modificano le voci nel modulo. Forse si potrebbe aver trovato una via di mezzo e utilizzato un numero intero che rappresenta un insieme di flag di bit, invece?

Sì, direi che è davvero così male. E 'una scelta difendibile, ma questo non lo rende correggere o buono.

Si rompe prima forma normale.

Una seconda critica è che mettere i risultati di input prime direttamente in un database, senza alcuna convalida o vincolante a tutti, le foglie si apre ad attacchi di SQL injection.

Quello che stai chiamando la pigrizia e la mancanza di conoscenza di SQL è la roba che neofiti sono fatte di. Mi consiglia di prendere il tempo per farlo correttamente e visualizzarlo come un'opportunità per imparare.

o lasciarlo così com'è e imparare la dolorosa lezione di un attacco di SQL injection.

Beh ho usato una scheda coppia chiave / valore elenco separato in una colonna NTEXT in SQL Server per più di 4 anni e funziona. Si perde la flessibilità di fare domande, ma d'altra parte, se si dispone di una libreria che persiste / derpersists la coppia chiave-valore, allora non è una cattiva idea quella.

I necessaria una colonna più valori, può essere implementato come un campo XML

Potrebbe essere convertito in virgola delimitato come necessario

interrogazione di un elenco XML in SQL Server utilizzando query XQuery .

Essendo un campo XML, alcune delle preoccupazioni possono essere affrontate.

Con CSV: non può garantire che ogni valore è il tipo di dati a destra: non c'è modo di evitare che 1,2,3, banana, 5

Con XML: i valori in un tag possono essere costretti a essere il tipo corretto


Con CSV: Non è possibile utilizzare i vincoli di chiave per i valori di collegamento a una tabella di ricerca; non c'è modo di applicare l'integrità referenziale.

Con XML: ancora un problema


Con CSV: non può far valere l'unicità: non c'è modo di evitare che 1,2,3,3,3,5

Con XML: ancora un problema


Con CSV:. Non è possibile eliminare un valore dalla lista senza caricare l'intera lista

Con XML: Elementi singoli possono essere rimossi


Con CSV: Hard per la ricerca di tutte le entità con un dato valore nella lista; è necessario utilizzare un inefficiente tavolo-scan.

Con XML: XML può essere indicizzata


Con CSV:. difficile contare gli elementi nella lista, o fare altre query di aggregazione **

Con XML: non particolarmente difficile


Con CSV:. Difficile unire i valori di tabella di ricerca fanno riferimento **

Con XML: non particolarmente difficile


Con CSV:. Difficile recuperare l'elenco in ordine ordinato

Con XML: non particolarmente difficile


Con CSV:. Memorizzazione interi come stringhe è di circa il doppio dello spazio di memorizzazione di interi binari

Con XML: di archiviazione è anche peggio di un csv


Con CSV:. più un sacco di personaggi virgola

Con XML: sono usati al posto di virgole


In breve, utilizzando XML ottiene intorno alcuni dei problemi con la lista delimitato e può essere convertito in un elenco delimitato, se necessario

Si, è così male. La mia opinione è che se non si fa come l'utilizzo di database relazionali poi cercare un'alternativa che più vi si addice meglio, ci sono un sacco di interessanti progetti "NoSQL" là fuori con alcune caratteristiche davvero avanzate.

I probabilmente prendere la via di mezzo: rendere ogni campo nel CSV in una colonna separata nel database, ma non preoccupatevi tanto di normalizzazione (almeno per ora). Ad un certo punto, la normalizzazione potrebbe interessante diventato, ma con tutti i dati spinti in una sola colonna si sta guadagnando praticamente alcun beneficio dall'utilizzo di un database a tutti. È necessario separare i dati in campi logici / colonne / tutto ciò che si desidera chiamare prima di poter manipolare significato a tutti.

Se si dispone di un numero fisso di campi booleani, si potrebbe usare un INT(1) NOT NULL (o BIT NOT NULL se esiste) o CHAR (0) (nullable) per ciascuno. Si potrebbe anche usare un SET (non ricordo la sintassi esatta).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top