2009-06-23 10 views
17

Sto appena entrando in un progetto e ha un backend di database piuttosto grande. Ho iniziato a scavare attraverso questo database e il 95% dei campi è annullabile.È un uso eccessivo di colonne nullable in un database un "odore di codice"?

Questa pratica normale è nel mondo del database? Sono solo un programmatore modesto, non un DBA, ma penso che vorrai mantenere i campi nullable al minimo, solo dove hanno senso.

È un "odore di codice" se la maggior parte delle colonne è annullabile?

+1

Se lo schema del DB è ancora in evoluzione e vengono aggiunte nuove colonne, potrebbe essere più semplice rendere le nuove colonne nulle all'inizio che possono significare molti null se ci sono molte colonne aggiunte alle tabelle all'interno del DB . Sembra essere dove li vedrei spuntare fuori. –

risposta

1

Come best practice, se una colonna non deve essere annullabile, deve essere contrassegnata come tale. Tuttavia, non credo di andare completamente fuori di testa con cose come questa.

1

Penso di sì. Se non hai bisogno dei dati, allora non è importante per la tua attività. Se è importante per la tua azienda, dovrebbe essere richiesto.

+0

Certo, un numero di carta di credito è necessario prima che un utente possa acquistare qualsiasi cosa (per esempio) ma dovrebbe comunque essere autorizzato a salvare altri attributi, e quindi aggiungere il numero di carta di credito più tardi. Se impedisci loro di inserire * qualsiasi * dati perché non hanno i campi richiesti, questo li renderà semplicemente sconvolti. –

+1

Ecco perché queste cose non appartengono alla stessa tabella, non perché il numero della carta di credito dovrebbe essere annullabile nella tabella degli ordini con carta di credito, giusto? –

+0

È solo un esempio. Il punto è che potrebbero esserci attributi di una data tabella che sono importanti per la tua azienda, ma non per l'integrità dei dati. –

16

I valori predefiniti sono in genere l'eccezione e NULL sono la norma, nella mia esperienza.

Veri, i nulli sono fastidiosi.

È anche estremamente utile perché null è l'indicatore migliore di "NO VALORE". Un valore predefinito concreto è molto fuorviante e puoi perdere informazioni o creare confusione lungo la strada.

+1

l'OP non dice se stanno usando MySQL. Il manuale MySQL dice: "Se possibile, dichiara che le colonne NON sono NULL. Rende più veloci le operazioni SQL, consentendo un migliore utilizzo degli indici ed eliminando l'overhead per verificare se ogni valore è NULL. Inoltre, si salva un po 'di spazio di archiviazione, un bit per colonna. ... "http://dev.mysql.com/doc/refman/5.5/en/data-size.html –

7

Non so se lo considero sempre una cosa negativa, ma se le colonne vengono aggiunte perché un singolo record (o forse alcuni) hanno bisogno di avere valori mentre la maggior parte no, allora indica un bel piatto struttura della tabella. Se vedi nomi di colonne come "addr1", "addr2", "addr3", allora puzza!

Scommetto che la maggior parte delle colonne che hai potrebbero essere rimosse e rappresentate in altre tabelle. È possibile trovare quelli "non nulli" attraverso una relazione di chiave esterna. Ciò aumenterà i join che farai, ma potrebbe essere più preformante che fare "where not col1 is null".

+1

Come memorizzare le varie righe di un indirizzo diverso dalle colonne denominate addr1, addr2, addr3? (O ti riferivi a 3 indirizzi completi separati?) Gli indirizzi sono uno dei casi di esempio standard per null. Alcuni indirizzi hanno 2 righe, alcuni hanno 6. – jmucchiello

+2

Ho interpretato Addr1 tramite AddrX come segnaposti per mailingAddress, physicalAddress, workAddress, xmasAddress, ecc. Altrimenti, sarebbe AddrLine1, AddrLine2. –

+0

Sì, forse l'indirizzo era un cattivo esempio - probabilmente avrebbe dovuto usare numeri di telefono. Ciò che tipicamente appare (in schemi errati) è "homeaddr", "workaddr", "vacationaddr", "otheraddr", "otheraddr2", ecc., Tutto perché un record ha bisogno di "workaddr", un altro "holidayaddr" necessario (senza " workaddr "), e così via. AddrLine1 e AddrLine2 vanno bene. –

1

Tutto ciò dipende completamente dall'ambito e dai requisiti del progetto. Non userei solo il numero di campi nullable come metrica per codice scritto male o progettato. Dai un'occhiata al dominio aziendale, se ci sono molti campi non annullabili rappresentati lì che sono annullabili nel database, quindi hai alcuni problemi.

2

No, se un campo deve essere annullabile o meno è un concetto di dati e non può essere un odore di codice. Se i NULL siano noiosi o meno di codice non ha nulla a che fare con l'utilità di avere campi di dati annullabili.

2

Sono un odore (molto comune), temo. Cercare C.J. Date scritti sull'argomento.

+0

Davvero? C. J. Data ritiene che i NULL non siano una parte legittima del modello relazionale e, anche se lo fossero, sono stati implementati in modo errato in SQL. Quindi i suoi scritti su questo argomento potrebbero essere considerati un'opinione estrema. –

+3

Potrebbero essere considerati un'opinione estrema se non fosse per il fatto che ha ragione, e ha un caso abbastanza ermetico per il motivo per cui ha ragione (almeno per quanto riguarda la parte "[nulls]" va). Un generatore di tipi come Opzionale o Forse (o qualsiasi altra cosa tu voglia chiamarlo) è una cosa utile, ma quando Manca = Manca valuta un terzo magico booleano chiamato Sconosciuto con tutti i tipi di proprietà stravaganti e incoerenti, questo è un problema per tutti (incluso l'ottimizzatore). –

13

Chiunque abbia sviluppato un'applicazione per l'immissione dei dati sa quanto sia comune che alcuni dei campi siano sconosciuti al momento dell'iscrizione, anche per le colonne critiche per l'azienda, per rispondere alla risposta di @Chris McCall.

Tuttavia, un "odore di codice" è semplicemente un indicatore del fatto che qualcosa di potrebbe essere codificato in modo trascurato. Usi gli odori per identificare le cose che richiedono più indagini, non necessariamente cose che devono essere cambiate.

Quindi sì, se vedi colonne annullabili in modo coerente, hai ragione ad essere sospettoso. potrebbe indicare che qualcuno è stato pigro o ha paura di dichiarare le colonne NOT NULL in modo inequivocabile. Puoi giustificare la tua analisi.

5

Penso che le colonne nullable dovrebbero essere evitate. Ovunque la semantica del dominio rende possibile utilizzare un valore che indica chiaramente i dati mancanti, dovrebbe essere utilizzato al posto di NULL.

Ad esempio, immaginiamo una tabella che contenga un campo Comment. La maggior parte degli sviluppatori posizionerebbe un NULL qui per indicare che non ci sono dati nella colonna. (E, si spera, un vincolo di controllo che non consente le stringhe di lunghezza zero in modo che abbiamo un ben noto "valore" per indicare la mancanza di un valore.) Il mio approccio è in genere il contrario. La colonna Comment è NOT NULL e una stringa di lunghezza zero indica la mancanza di un valore. (Uso un vincolo di controllo per garantire che la stringa di lunghezza zero sia realmente una stringa di lunghezza zero e non spazi bianchi.)

Quindi, perché dovrei farlo? Due motivi:

  1. NULL s richiedono una logica speciale in SQL e questa tecnica evita questo.
  2. Molte librerie sul lato client hanno valori speciali per indicare NULL. Ad esempio, se si utilizza ADO.NET di Microsoft, la costante DBNull.Value indica un valore NULL e si deve verificarlo. L'utilizzo di una stringa di lunghezza zero su una colonna NOT NULL elimina la necessità.

Nonostante tutto ciò, ci sono molte circostanze in cui gli NULL vanno bene. In realtà, non ho obiezioni al loro uso nello scenario sopra, anche se non sarebbe il mio modo preferito.

Qualunque cosa tu faccia, sii gentile con quelli che useranno i tuoi tavoli. Essere coerente. Consentire loro di SELECT con fiducia. Lasciami spiegare cosa intendo con questo. Recentemente ho lavorato a un progetto il cui database non è stato progettato da me. Quasi ogni colonna era annullabile e non aveva vincoli. Non c'era coerenza su ciò che rappresentava l'assenza di un valore. Potrebbe essere NULL, una stringa di lunghezza zero, o anche un mucchio di spazi, e spesso lo era. (Come che la minestra di valori arrivato, non lo so.)

immaginare il codice di brutto uno sviluppatore deve scrivere per trovare tutti i record con un Comment campo mancante in questo scenario:

SELECT * FROM Foo WHERE LEN(ISNULL(Comment, '')) = 0 

Sorprendentemente ci sono sviluppatori che lo considerano perfettamente accettabile, anche normale, nonostante le possibili implicazioni in termini di prestazioni. Meglio sarebbe:

SELECT * FROM Foo WHERE Comment IS NULL 

O

SELECT * FROM Foo WHERE Comment = '' 

Se la tabella è progettato correttamente, queste due istruzioni SQL può essere invocata per produrre dati di qualità.

+5

Devo non essere d'accordo. NULL significa sconosciuto, indipendentemente dal tipo di dati della colonna. Dovrebbe sempre essere usato per significare sconosciuto, e valori magici come la stringa vuota non dovrebbero mai essere usati per significare sconosciuto. –

+0

D'altra parte, se sappiamo che l'utente ha scelto di non lasciare un commento, perché dovremmo usare qualcosa che significa "sconosciuto" per rappresentare tale conoscenza? –

+0

@ john-saunders Dipende dal dominio. Una stringa di lunghezza zero in un campo di commento può rappresentare un valore molto ben definito, estremamente noto: "nessun commento". Questo è abbastanza diverso da "sconosciuto". Tuttavia, questi sono giochi semantici che persino il Dr. Codd ha giocato. Più tardi ha inventato diverse alternative a NULL per indicare cose come sconosciuto, mancante, ecc. L'importante è essere * coerenti *. –

1

Nella mia esperienza, è un problema quando Null e Not Null non corrispondono al campo richiesto/campo non richiesto.

È nel regno della possibilità che quelli sono davvero tutti campi opzionali. Se nel livello aziendale o nel livello dell'interfaccia utente si trova che tali campi sono obbligatori, penso che questo significhi che il modello di dati si sia allontanato dal modello degli oggetti di business e sia un segno di politiche di modifica dei DB eccessivamente conservative o di supervisione.

Se si esegue un generatore di dati di esempio sui dati, e quindi provare a caricare i dati che è valida in base a SQL, si dovrebbe sapere subito se le regole corrispondono.

0

che sembra molto, probabilmente significa che si dovrebbe almeno indagare. Nota che se questo è un prodotto maturo con molti dati, convincere chiunque a cambiare la struttura potrebbe essere difficile. Quanto prima nella fase di progettazione si cattura qualcosa del genere, tanto più facile è aggiustare tutto il codice relativo per adattarsi alla modifica.

Se sia sbagliato utilizzare i valori nulli, dipende dal fatto che le colonne che consentono i valori nulli sembrino essere tabelle correlate (telefono di casa, telefono cellulare, telefono aziendale ecc. Che dovrebbe essere nella tabella del telefono aspearato) o se assomigliare a cose che potrebbero non essere applicabili a tutti i record (probabilmente potrebbe riferirsi alla tabella correlata con una relazione uno-a-uno) o potrebbero non essere note al momento dell'inserimento dei dati (probabilmente ok). Vorrei anche verificare se effettivamente hanno un valore (allora potreste essere in grado di passare a null se l'informazione è realmente richiesta dalla logica del business). Se si dispone di un paio di record con nulla

0

Nella mia esperienza, un campo nullable molto in un database di grandi dimensioni come si dispone è molto normale. Considerandolo forse è usato da molte applicazioni scritte da persone diverse. Rendere le colonne nullable è fastidioso, ma è forse il modo migliore per mantenere l'applicazione robusta.

+1

È deprimamente comune; non è buono e generalmente non rende l'applicazione solida. –

0

Uno dei molti modi per mappare l'ereditarietà (ad es. Oggetti C#) in un database consiste nel creare una tabella per la classe nella parte superiore della gerarchia, quindi aggiungere le colonne per tutte le altre classi. Le colonne devono essere annullabili quando un oggetto di una sottoclasse diversa viene memorizzato nel database. Questo è chiamato Single-table inheritance mapping (o Map Hierarchy To A Single Table) ed è un modello di progettazione standard.

Un effetto collaterale di mappatura ereditarietà singola tabella è che la maggior parte colonne sono annullabili.


Anche in Oracle una stringa vuota (0 lunghezza) è considerato nullo, quindi in alcune aziende tutte le stringhe colonne sono fatte annullabile anche su SqlServer. (solo perché il primo cliente vuole il software su SqlServer non significa che il 2 ° cliente non ha un DBA Oracle che non permetterà a SqlServer di collegarsi alla rete)

+0

Tuttavia, quando arriva allo stadio che la maggior parte delle colonne sono nulle, penso che sia il momento di considerare la mappatura su più tabelle. Ciò renderà possibile applicare alcuni vincoli sulle tabelle derivate. –

+0

Ma cambiare il sistema ORM utilizzato dall'applicazione può essere un grosso rischio. Alla fine, il database è lì per servire l'applicazione, non il contrario.(Io sono un programmatore C#, dopotutto non è un DBA) –

+0

Chi ha detto qualcosa sulla modifica del sistema ORM? Basta modificare il modo in cui ORM esegue il mapping al database sottostante. Inoltre, ciò può consentire l'applicazione di ulteriori vincoli, migliorando la qualità del sistema nel suo complesso. –

8

Sono del campo Extreme NO: evito NULLs tutto il tempo. Mettendo da parte considerazioni fondamentali su cosa significano realmente (perché parlare con persone diverse, otterrai risposte diverse come "nessun valore", "valore sconosciuto", "mancante", "il mio gatto allo zenzero chiamato Null"), il problema peggiore La causa NULL è che spesso rovinano le tue domande in modi misteriosi.

Ho perso il conto del numero di volte che ho dovuto eseguire il debug di query di qualcuno (ok, forse 9) e tracciato il problema ad un unirsi contro un NULL. Se il tuo codice ha bisogno di ISNULL per riparare i join, è probabile che tu abbia perso anche l'applicabilità dell'indice e le prestazioni con esso.

Se si do è necessario memorizzare un valore "missing/unknown/null/cat" (ed è qualcosa che preferisco evitare), è meglio essere espliciti al riguardo.

Gli esperti di NULL potrebbero non essere d'accordo. L'uso NULL tende a dividere le folle SQL nel mezzo.

Nella mia esperienza, l'uso NULL pesante è stata correlata positivamente con l'abuso di database, ma non vorrei ritagliarsi questo in tavole di pietra come una legge della natura. La mia esperienza è solo la mia esperienza.

MODIFICA: pensiero aggiuntivo.È possibile che coloro che sono razzisti anti-null come me siano più eccitati dalla normalizzazione di quelli che sono pro-NULL. Non penso che i normalizzatori rabbiosi sarebbero troppo contenti con i bordi frastagliati sui loro tavoli che possono prendere NULL. Un sacco di null può indicare che gli sviluppatori del database non sono in pesante normalizzazione. Quindi, piuttosto che NULL suggerire che il codice è "cattivo", può suggerire alternativamente la posizione filosofica degli sviluppatori sulla normalizzazione. Forse sta arrivando. Solo un pensiero.

+1

Come ti senti rispetto al valore intero zero, che si traduce in errori di divisione per zero se usati impropriamente? Questo significa che dovremmo vietare l'uso di zero? –

+1

Inoltre, l'esempio del tuo gatto è spurio. La stringa "Null" non è la stessa di SQL NULL. Ma mi fa pensare a come faresti un poster alla ricerca di quel gatto se sparisse. ;-) –

+0

Se è il gatto di Schrodinger, allora può essere vivo o morto, quindi lo rende rilevante in una sorta di "che cos'è?" way =) Gli errori Div da zero sono coerenti, in faccia e abbastanza ovvi; è un problema aritmetico fondamentale con cui devi convivere. NULL tende ad essere furtivo come un ninja, non sei sicuro di aver avuto un problema NULL fino a quando non lo hai avuto - più il comportamento del join NULL può essere incoerente tra le piattaforme. Direi che non è un concetto fondamentale con un significato definitivo e un insieme standard di comportamenti, a differenza di div a zero. (E 'Null'! = SQL NULL ha catturato molti sviluppatori) –

4

In breve, direi di sì, questo è probabilmente un odore di codice.

Se una colonna è annullabile o meno è molto importante e deve essere determinata con attenzione. La domanda dovrebbe essere valutata per ogni colonna. Non sono un credente in un unico predefinito "best practice" per NULL. La "migliore pratica" per me è quella di affrontare a fondo l'annullabilità durante la progettazione e/o il refactoring del tavolo.

Per iniziare, nessuna delle colonne chiave primaria diventerà annullabile. Quindi, mi spingo fortemente verso NOT NULL per tutto ciò che è una chiave esterna.

Alcune altre cose che considerano:

Criteri dove NULL dovrebbe essere fortemente evitare: money colonne - c'è davvero una possibilità che tale importo sarà sconosciuto?

Criteri dove NULL può essere giustificato più di frequente: datetime colonne - non ci sono date riservate, in modo NULL è efficace l'opzione migliore

altri tipi di dati: char/varchar colonne - per codici/identificatori - NOT NULL quasi esclusivamente int colonne - per lo più NOT NULL a meno che non si tratti di qualcosa come "numero di bambini" in cui si desidera distinguere una risposta sconosciuta.

0

Per lanciare l'opinione opposta là fuori. Ogni singolo campo in un database dovrebbe annullabile. Non c'è niente di più frustrante di lavorare con un database che su ogni singolo inserto fa un'eccezione su ciò richiesto o richiesto. Nulla dovrebbe essere richiesto.

C'è un'eccezione, chiavi. Ovviamente tutte le chiavi primarie e quelle straniere dovrebbero essere applicate per esistere.

Dovrebbe essere compito dell'applicazione convalidare i dati e il database per archiviare e recuperare semplicemente ciò che gli viene dato. Avere una logica di validazione del processo anche semplice come null o not null rende un progetto molto più complesso da mantenere per avere regole diverse distribuite su tutto.

Problemi correlati