2009-02-10 11 views
8

Devo mantenere un'applicazione che ha molte colonne che sono del tipo di dati di testo, con più valori inseriti al loro interno delimitati da virgole, barre o talvolta anche il carattere pipe (|). Sto cercando di capire perché mai vorresti farlo sulla Terra.Perché dovresti memorizzare un elenco delimitato in una colonna di testo SQL?

Ad esempio, una tabella di ordini ha una colonna denominata dati che contiene informazioni quali:

2x #ABC-12345 Widget, Black: $24.99 /4x #ABC-12344 Widget, Blue: $23.50 

dove il / separa gli elementi; c'è un codice VBScript che legge il valore da un recordset e lo analizza in un ciclo For per la visualizzazione usando qualcosa di simile (e questo è praticamente esattamente come il codice legge, i nomi delle variabili e tutto) arydtls = split(rstmp("details"), "/"). Questo metodo viene ripetuto in tutto il codice per varie tabelle.

Mi sembra come esso sarebbe 100x meglio (per non parlare più facile lavorare con) per solo avere i dettagli in una tabella separata e un collegamento ad esso (stranamente, per gli ordini che non fare questo, ma i dati non sempre corrispondono al campo di testo dei dettagli perché la tabella OrderDetail viene aggiornata nel codice, il campo dei dettagli viene trattato come di sola lettura nell'applicazione).

Il mio predecessore ha saputo qualcosa che io non ho, o ho ragione di dire "WTF? !!" quando guardo questo schema? Sembra che sia follemente inefficiente e difficile da mantenere in questo modo, e rende i rapporti in esecuzione più difficili perché i dati di cui ho bisogno potrebbero essere contenuti nei campi di testo O potrebbe essere in una dozzina di tabelle che hanno informazioni simili e sono utilizzate in diversi parti dell'applicazione

risposta

2

Il mio predecessore ha saputo qualcosa che io non ho, o ho ragione di dire "WTF? !!" quando guardo questo schema?

No, il suo predecessore no. Si hai ragione. Vedi nota alla fine, comunque.

Sembra come se fosse follemente inefficiente e difficile da mantenere in questo modo, e rende l'esecuzione di report in più difficili perché i dati che ho bisogno possa far parte di campi di testo o potrebbe essere in uno di una dozzina di tavoli che hanno simili informazioni e vengono utilizzate in diverse parti dell'applicazione.

E è follemente inefficiente. Vedi nota alla fine, comunque.

Una colonna deve sempre essere un attributo indivisibile della riga. Vedo due copie di tre (forse quattro) attribuisce in questa colonna che avete mostrato:

2x #ABC-12345 Widget, Black: $24.99 /4x #ABC-12344 Widget, Blue: $23.50 
  • quanity (2x/4x).
  • codice
  • (# ABC-12345/# ABC-12344).
  • descrizione (Widget, Nero:/Widget, Blu :) [può essere descrizione e attributi colore].
  • prezzo ($ 24,99/$ 23,50).

questo sarebbe stato meglio progettati come:

StockItems 
    Code char(10) primary key 
    Desc varchar(50) 
Transaction 
    TxnId something primary key 
    : : : 
TransactionPart 
    TxnId something \ 
    TxnSeq int /primary key 
    Quantity integer 
    Code char(10) foreign key StockItems(Code) 
    Price float 

NOTA:

E 'possibile che questo è stato fatto per conservare informazioni storiche di fronte alla modifica dei valori in altre parti del database. Ad esempio, se la descrizione di un articolo stock cambia o l'elemento viene eliminato.

Tuttavia, questo è ancora non è il modo giusto per gestirlo.In quel caso, i vincoli di chiave esterna avrebbero impedito l'eliminazione del codice articolo e avrebbero dovuto essere applicati i processi per impedire l'aggiornamento della descrizione (come il controllo delle versioni dei codici articolo stock).

Ovviamente, se si sta mai andando alla ricerca su uno qualsiasi degli elementi all'interno di quella colonna, questo è perfettamente valido, anche se poco saggio in termini di possibili funzionalità future da cercare su di essi.

Forse l'unica cosa che mai cercato sul in questa tabella è il codice cliente - poi un campo di testo in formato libero è adeguato.

I ancora non lo farebbe in questo modo, ma un argomento YAGNI può essere fatto che sarebbe meglio cambiare lo schema DB in futuro, se e quando tale funzionalità di ricerca deve essere aggiunto.

8

I due scenari più probabili sono:

  • Il suo predecessore è stato incompetente/non capiva la normalizzazione
  • Il suo predecessore ha incontrato alcuni problemi di prestazioni con la struttura normalizzata e ha trovato questo metodo è stato un miglioramento

Poiché la normalizzazione può spesso essere molto costosa quando si tratta di operazioni di query, a volte si possono ottenere miglioramenti delle prestazioni eliminando un join costoso e facendo le manipolazioni dal lato dell'applicazione contro una singola riga.

Non esiste una regola assoluta per la progettazione del database che dice "memorizzare valori delimitati in una singola riga è meglio per questo scenario". Si tratta di testare contro i tuoi specifici set di dati e i tuoi modelli di utilizzo e apportare miglioramenti laddove necessario.

Nella mia esperienza non è molto comune che questo modello sia un miglioramento rispetto alla normalizzazione, anche se ... è piuttosto atipico.

Modifica: una terza possibilità è che avere valori n per riga era una modifica rispetto allo schema originale e invece di aggiungere una nuova tabella il predecessore ha ridimensionato la colonna. Ciò non è necessariamente diverso dall'opzione "incompetente" :) ma a volte ci sono pressioni politiche coinvolte nelle modifiche dello schema db ...

+0

Questo è quello che pensavo. La metterò così: potrei fornire al Daily WTF probabilmente un mese di articoli basati solo sul codice di questo ragazzo. –

+0

Consentitemi di aggiungere un altro potenziale scenario: * I dati di testo sono stati importati da un sistema legacy (eventualmente tabelle excel/word) e sono stati concepiti come memoria temporanea finché i dati non sono stati analizzati in una struttura normalizzata. La doppia archiviazione dei dati degli ordini sembra puntare a questo. – JohnFx

+0

@JohnFx - buon punto, anche se immagino che il richiedente sarebbe consapevole del fatto che questi dati sono stati portati da un sistema legacy e il suo predecessore non ha progettato il DB. –

0

WTF davvero. Non memorizzare mai cose del genere nel DB.

0

Il tuo predecessore aveva forse qualche altra idea e questo è stato lasciato incompiuto ???

posso dirvi che questo è molto male per le prestazioni

Come ti creare una query che restituirà che ha comprato un widget blu? Dovrai eseguire la scansione dell'intera tabella e analizzare queste informazioni, se ci fosse un'altra tabella e questo sarebbe stato normalizzato, allora sarebbe molto meglio le prestazioni

+0

A giudicare da come l'ha fatto, penso che ha aggiunto che in seguito ... ci * è * una tabella Dettagli che (a volte) contiene le stesse informazioni della colonna dei dettagli grandi, ma viene utilizzata in altre aree dell'applicazione. Non ha senso per me perché l'abbia fatto in quel modo! –

0

Ho visto un database in un determinato pezzo di software aziendale che ha questo in tonnellate di posti. È piuttosto terribile, sia dal punto di vista della manutenzione che dal punto di vista delle prestazioni. I motivi citati sono in genere:

  • è "semplice", perché non richiede unisce
  • è più veloce perché non richiede unisce
  • che non ingombrare il database con un sacco di tavoli

Ora, il primo punto è probabilmente vero, ma è solo "più semplice" finché non si desidera eseguire una query su di esso. Ora sei fregato. Quindi direi che è efficacemente confutato. Il secondo punto è di nuovo vero, purché non lo si stia interrogando. Non appena devi leggere l'intera tabella, analizzare i dati, quindi filtrare le righe nella tua app, perdi. L'ultimo è sempre vero, ma a chi importa se il database è "ingombrante"? Ecco a cosa serve! Decenti RDBMS ti permetteranno di mettere le tue tabelle in più schemi comunque, che sono in qualche modo come spazi dei nomi e aiutano a combattere il disordine. Anche una buona convenzione di denominazione aiuta (ma se usi le verruche ungheresi, così ti aiuti $ divinità).

In breve, è una cattiva idea. Spero che ti sia permesso di risolverlo, ma molto probabilmente avrai a che fare con i termini originali ...

0

In sistemi operativi come Universo, i dati UniData sono memorizzati in file delimitati da qualcosa come

Char (254) = separa proprietà char (253) = separa valori multipli in una struttura Char (252) = separa valori sub ecc

shock non è vero: - Ogni volta che parlo con ex colleghi che lavorano ancora con DataBasic e chiedono che DB uso la prima domanda che chiedono è "Gestisce valori multipli ok?"

In un RDBMS avremmo una tabella Ordini e una tabella OrderLine. Il PK su OrderLine molto probabilmente sarà qualcosa come OrderNumber, LineNumber.

In UniData ecc., Ciò che farebbero è avere una proprietà in Ordine chiamata "Linee" che terrebbe una lista di chiavi per il file OrderLine, la chiave composta solitamente separata con un asterisco.

  • 1234 * 1
  • 1234 * 2
  • 1234 * 3
  • ecc

Poi, quando caricano il loro ordine in memoria dal file hanno un elenco di chiavi di cui hanno bisogno per caricare OrderLines dal file OrderLine.Si noti che questi sono file e non tabelle :-)

Mi sembra che qualcuno con esperienza con questo vecchio modo di archiviare dati abbia provato a utilizzare un database relazionale, non l'abbia compreso del tutto, e poi ha provato a farlo funzionare come UniData.

Sack loro :-)

1

Semplicemente si sia avuto un motivo o non l'ha fatto, senza chiedere la sua impossibilità di conoscere. Se si assume che non fosse un'idea totale e una questione di alcune possibili ragioni, allora forse è una delle seguenti.

Se i dati era solo per informazione e "non cambierà mai" come si sente così spesso allora può essere stato un rapido vittoria solo per gettare uno stringa di visualizzazione direttamente al campo. Dopotutto, la semplice sostituzione dei tubi con le schede e le barre con BR's per metterlo sullo schermo è incredibilmente facile. Se il codice ha scritto in modo estremamente rapido, questa potrebbe essere stata l'opzione più semplice.

Una nuova funzionalità da SQL 2005 è il tipo di dati XML. Un uso importante di questo è che è possibile memorizzare e indicizzare un numero sconosciuto di valori rispetto a un particolare record. Potresti preoccuparti del colore di una cosa, delle dimensioni di un'altra, del peso di qualcos'altro. Potresti non essere in grado di produrre un elenco definitivo di queste cose e un metodo generico veramente normalizzato per la memorizzazione di questi dati potrebbe essere troppo lento o eccessivamente complicato per il sistema. Questo potrebbe essere stato un tentativo di provare e ottenere funzionalità simili.

La cosa fondamentale qui è che molte cose sono fatte per una ragione. L'hai guardato nel modo giusto cercando di scoprire questa ragione. Potresti incontrarlo un giorno e pensare "Oh sì!". Solo guardando qualcosa dalla propria prospettiva spesso si può arrivare a non vedere lo scenario del bosco per gli alberi.

0

Non posso dire cosa pensasse il tuo predecessore. Come ha detto Rex M, a volte le pressioni politiche portano a strane implementazioni.

Un gran numero di persone che inseriscono un elenco di elementi in un singolo valore nelle tabelle sta tentando di aggirare le restrizioni del (vecchio stile) prima forma normale. Il lato negativo è che le domande devono essere eseguite in modo programmatico nell'app anziché utilizzare una semplice citerione in una clausola WHERE.

Circa 10 anni fa, Oracle ha aggiunto la possibilità di inserire un valore all'interno di una tabella. Circa allo stesso tempo, Data ridefinita 1NF in modo che tutte le relazioni siano automaticamente in 1NF. Ciò include le reazioni che contengono altre relazioni. Senza questa caratteristica, il design più semplice e potente è quello di spezzare l'elemento ripetuto in un valore separato, con una riga per ogni elemento.

(Esempio: un elenco di corsi uno studente è iscritto)

In molti casi, il coause radice è l'ignoranza progettisti o testardaggine. Ancora una volta, non so quali restrizioni il tuo predecessore abbia affrontato. Non imitarlo a meno che non sia necessario.

0

Perché dovresti fare qualcosa del genere?

Tornato a parlare di borbotti decenni fa, mia moglie ha lavorato al sistema Pick, che includeva un database e un BASIC e così via. Il database Pick e il linguaggio hanno funzionato bene mettendo gli array nei campi del database (non sono sicuro se dovrei chiamarli colonne). Quindi, c'era un ambiente in cui tutto ciò aveva perfettamente senso.

Non so se Pick è ancora in giro, ma non ne ho sentito parlare da molto tempo.È possibile che questa tabella fosse un database Pick tradotto (male) in un database basato su SQL ed è possibile che chiunque l'abbia scritto fosse un ex sviluppatore di Pick che non aveva imparato a utilizzare un database relazionale al momento.

L'ultima volta che mi sono imbattuto in un database come quello, ho chiesto. È risultato essere stato progettato da un ex sviluppatore di Pick.

Non definirei questo design competente, a meno che non fosse inteso come un campo ignorabile solo per scrittura, ma potrebbe anche essere che il progettista non fosse stupido.

+0

Le tabelle sono state appena create con SQL Server e sono state eseguite solo pochi anni fa, quindi ne dubito. Penso davvero che non riuscisse a pensare a un modo migliore di farlo e l'ha fatto solo nel modo più veloce a cui potesse pensare. –

+0

Dato che, probabilmente hai ragione. Sembrava almeno una spiegazione più caritatevole di qualsiasi altra cosa che mi veniva in mente. –

0

Un possibile motivo, in qualche modo valido, potrebbe essere che la struttura dati non sia corretta, gli attributi di dettaglio sono molto diversi con le istanze di ordine.

Non è facile lavorare con attributi dinamici in una struttura statica come quella imposta da un database. Una struttura XML ad esempio è più adatta per uno scenario di questo tipo, ma dando l'intrinseca prolissità di xml, l'approccio 'csv like' avrebbe potuto essere un'alternativa più attraente.

0

Mi sembra un WTF. Non è coerente con il modo in cui vengono implementate altre tabelle e sicuramente non è efficiente. E quando si guarda lo schema senza conoscere i dati all'interno, sarebbe facile fraintendere il senso di una colonna.

Tuttavia, ci potrebbe essere una ragione per cui lo sviluppatore passato ha fatto questo, ci può dare più informazioni, come sulla sulla logica di business? Grazie

Problemi correlati