it-swarm.it

Perché non dovremmo consentire i NULL?

Ricordo di aver letto questo articolo sulla progettazione del database e ricordo anche che dicevo che dovresti avere proprietà sul campo di NOT NULL. Non ricordo perché questo fosse il caso.

Tutto ciò a cui riesco a pensare è che, come sviluppatore di applicazioni, non dovresti testare NULL e un possibile valore di dati inesistente (ad esempio, una stringa vuota per le stringhe).

Ma cosa fai in caso di date, data e ora (SQL Server 2008)? Dovresti usare una data storica o dal basso.

Qualche idea su questo?

127
Thomas Stringer

Penso che la domanda sia mal formulata, poiché la formulazione implica che hai già deciso che i NULL sono cattivi. Forse intendevi "Dovremmo consentire i NULL?"

Comunque, ecco la mia opinione: penso che i NULL siano una buona cosa. Quando inizi a prevenire i NULL solo perché "NULL sono cattivi" o "NULL sono difficili", inizi a creare dati. Ad esempio, cosa succede se non conosci la mia data di nascita? Che cosa hai intenzione di mettere nella colonna fino a quando non lo sai? Se assomigli a un sacco di gente anti-NULL, entrerai nel 1900-01-01. Ora sarò messo nel reparto geriatrico e probabilmente riceverò una telefonata dalla mia stazione di notizie locale congratulandomi per la mia lunga vita, chiedendomi i miei segreti per vivere una vita così lunga, ecc.

Se è possibile inserire una riga in cui è possibile che non si conosca il valore di una colonna, penso NULL ha molto più senso che scegliere un valore di token arbitrario per rappresentare il fatto che è sconosciuto - un valore che altri dovranno già conoscere, decodificare o chiedere in giro per capire cosa significhi.

Tuttavia, esiste un equilibrio: non tutte le colonne del modello di dati devono essere nullable. In un modulo sono spesso presenti campi opzionali o informazioni che altrimenti non vengono raccolte al momento della creazione della riga. Ma ciò non significa che puoi rimandare il popolamento di tutti dei dati. :-)

Inoltre, la possibilità di utilizzare NULL può essere limitata da requisiti cruciali nella vita reale. In campo medico, ad esempio, può essere una questione di vita o di morte sapere perché un valore è sconosciuto. La frequenza cardiaca è NULL perché non era presente un impulso o perché non l'abbiamo ancora misurato? In tal caso, possiamo mettere NULL nella colonna della frequenza cardiaca e avere note o una colonna diversa con un motivo NULL, perché?

Non abbiate paura dei NULL, ma siate disposti a imparare o dettare quando e dove dovrebbero essere usati, e quando e dove non dovrebbero.

232
Aaron Bertrand

I motivi accertati sono:

  • NULL non è un valore e pertanto non ha un tipo di dati intrinseco. I null richiedono una gestione speciale in tutto il luogo quando il codice che si basa altrimenti su tipi reali potrebbe anche ricevere il NULL non tipizzato.

  • NULL rompe la logica a due valori (familiare True o False) e richiede una logica a tre valori. Questo è molto più complesso da implementare correttamente, ed è certamente poco compreso dalla maggior parte dei DBA e praticamente da tutti i non-DBA. Di conseguenza, invita positivamente a molti bug sottili nell'applicazione.

  • Il significato semantico di qualsiasi NULL specifico viene lasciato all'applicazione , a differenza dei valori effettivi.

    Semantici come "non applicabile" e "sconosciuto" e "sentinella" sono comuni, e ce ne sono anche altri. Sono frequentemente utilizzati contemporaneamente nello stesso database, anche all'interno della stessa relazione; e sono ovviamente significati inesplicabili, indistinguibili e incompatibili .

  • Essi non sono necessari per i database relazionali , come affermato in “Come gestire le informazioni mancanti senza valori null” . Un'ulteriore normalizzazione è un ovvio primo passo per provare a liberare una tabella di NULL.

Questo non significa che NULL non dovrebbe mai essere permesso. lo fa sostiene che ci sono molti buoni motivi per non consentire NULL ove possibile.

Significativamente, sostiene di provare molto - attraverso una migliore progettazione dello schema, migliori motori di database e linguaggi di database ancora migliori - a make è possibile evitare NULL più spesso.

Fabian Pascal risponde a una serie di argomenti, in "Nulls Nullified" .

61
bignose

Non sono d'accordo, i null sono un elemento essenziale nella progettazione del database. L'alternativa, come hai anche accennato, sarebbe una proliferazione di valori noti per rappresentare il mancante o l'ignoto. Il problema risiede nel fatto che nulla è così ampiamente frainteso e di conseguenza usato in modo inappropriato.

IIRC, Codd ha suggerito che l'attuale implementazione di null (che significa non presente/mancante) potrebbe essere migliorata con due marker null anziché uno, "non presente ma applicabile" e "non presente e non applicabile". Non riesco a immaginare come i progetti relazionali potrebbero essere migliorati da questo personalmente.

32

Vorrei iniziare dicendo che non sono un DBA, sono uno sviluppatore a memoria e mantengo e aggiorno i nostri database in base alle nostre esigenze. Detto questo, ho avuto la stessa domanda per alcuni motivi.

  1. Valori nulli rendono lo sviluppo più difficile e soggetto a bug.
  2. I valori null rendono le query, le stored procedure e le visualizzazioni più complesse e soggette a bug.
  3. I valori null occupano spazio (? Byte in base alla lunghezza della colonna fissa o 2 byte per la lunghezza della colonna variabile).
  4. Valori nulli possono e spesso influenzano l'indicizzazione e la matematica.

Passo molto tempo a vagliare il carico di risposte, commenti, articoli e consigli su Internet. Inutile dire che la maggior parte delle informazioni erano circa le stesse della risposta di @ AaronBertrand. Ecco perché ho sentito il bisogno di rispondere a questa domanda.

In primo luogo voglio impostare qualcosa di chiaro per tutti i lettori futuri ... I valori NULL rappresentano dati sconosciuti NON dati inutilizzati. Se si dispone di una tabella dei dipendenti con un campo data di fine. Un valore nullo nella data di scadenza è perché è un campo obbligatorio futuro che è attualmente sconosciuto. Ogni dipendente, sia esso attivo o licenziato, ad un certo punto avrà una data aggiunta a quel campo. Questa è secondo me l'unica e unica ragione per un campo Nullable.

Detto questo, la stessa tabella dei dipendenti conterrebbe molto probabilmente un tipo di dati di autenticazione. È comune in un ambiente aziendale che i dipendenti siano elencati nel database per risorse umane e contabilità, ma non sempre hanno o necessitano di dettagli di autenticazione. La maggior parte delle risposte ti indurrebbe a pensare che sia ok annullare quei campi o in alcuni casi creare un account per loro, ma non inviare loro mai le credenziali. Il primo indurrà il tuo team di sviluppo a scrivere codice per verificare la presenza di NULL e gestirli di conseguenza e il secondo comporta un enorme rischio per la sicurezza! Gli account che non sono ancora stati utilizzati nel sistema aumentano solo il numero di possibili punti di accesso per un hacker, inoltre occupano prezioso spazio nel database per qualcosa che non viene mai utilizzato.

Date le informazioni di cui sopra, il modo migliore per gestire i dati nullable che verranno utilizzati è consentire valori nullable. È triste ma vero e i tuoi sviluppatori ti odieranno per questo. Il secondo tipo di dati nullable deve essere inserito in una tabella correlata (IE: Account, Credenziali, ecc.) E avere una relazione One-to-One. Ciò consente a un utente di esistere senza credenziali a meno che non siano necessarie. Ciò rimuove il rischio aggiuntivo per la sicurezza, lo spazio prezioso del database e fornisce un database molto più pulito.

Di seguito è riportata una struttura della tabella molto semplicistica che mostra sia la colonna nullable richiesta sia una relazione One-to-One.

Unknown Nullable and One-to-One relationship

So di essere un po 'in ritardo alla festa da quando questa domanda è stata posta anni fa, ma spero che ciò contribuirà a far luce su questo problema e sul modo migliore di affrontarlo.

14

A parte tutti i problemi con gli sviluppatori confusi NULL, i NULL hanno un altro inconveniente molto serio: le prestazioni

Le colonne NULL'able sono un disastro dal punto di vista delle prestazioni. Considera l'aritmetica dei numeri interi come esempio. In un mondo sano senza NULL, è "facile" vettorializzare l'aritmetica di numeri interi nel codice del motore di database utilizzando le istruzioni SIMD per eseguire praticamente qualsiasi calcolo a velocità superiori a 1 riga per ciclo CPU. Tuttavia, nel momento in cui si introduce NULL, è necessario gestire tutti i casi speciali creati da NULL. I moderni set di istruzioni della CPU (leggi: x86/x64/ARM e anche la logica GPU) semplicemente non sono attrezzati per farlo in modo efficiente.

Considera la divisione come esempio. A un livello molto alto, questa è la logica necessaria con un numero intero non nullo:

if (b == 0)
  do something when dividing by error
else
  return a / b

Con NULL, questo diventa un po 'più complicato. Insieme a b avrai bisogno di un indicatore se b è nullo e allo stesso modo per a. Il controllo ora diventa:

if (b_null_bit == NULL)
   return NULL
else if (b == 0) 
   do something when dividing by error
else if (a_null_bit == NULL)
   return NULL
else 
   return a / b

L'aritmetica NULL è significativamente più lenta nell'esecuzione su una CPU moderna rispetto all'aritmetica non nulla (di un fattore di circa 2-3x).

Peggiora quando si introduce SIMD. Con SIMD, una moderna CPU Intel può eseguire 4 divisioni intere a 32 bit in una singola istruzione, in questo modo:

x_vector = a_vector / b_vector
if (fetestexception(FE_DIVBYZERO))
   do something when dividing by zero
return x_vector;

Ora, ci sono modi per gestire NULL anche in SIMD land, ma ciò richiede l'uso di più vettori e registri CPU e un po 'di mascheramento intelligente dei bit. Anche con buoni trucchi, la penalità prestazionale dell'aritmetica intera NULL si insinua nell'intervallo 5-10x più lento per espressioni anche relativamente semplici.

Qualcosa di simile a quanto sopra vale per gli aggregati e, in una certa misura, anche per i join.

In altre parole: l'esistenza di NULL in SQL è una discrepanza di impedenza tra la teoria del database e la progettazione attuale dei computer moderni. C'è una buona ragione per cui NULL confonde gli sviluppatori - poiché un numero intero non può essere NULL nella maggior parte dei linguaggi di programmazione sani - non è proprio così che funzionano i computer.

13
Thomas Kejser

Articolo di Wikipedia su SQL Null contiene alcune interessanti osservazioni sul valore NULL e come risposta indipendente dal database, purché tu sia a conoscenza dei potenziali effetti di avere valori NULL per il tuo RDBMS specifico, sono accettabile nel tuo design. Se non lo fossero, non saresti in grado di specificare le colonne come nullable.

Basta essere consapevoli di come RDBMS li gestisce nelle operazioni SELECT come la matematica e anche negli indici.

10
Derek Downey

Domande interessanti.

Tutto ciò a cui riesco a pensare è che, come sviluppatore di applicazioni, non dovresti testare NULL e un possibile valore di dati inesistente (ad esempio, una stringa vuota per le stringhe).

È più complicato di così. Null ha un numero di significati distinti e una ragione davvero importante per non consentire valori nulli in molte colonne è che quando la colonna è nulla, ciò significa una sola cosa (ovvero che non è stata mostrata in un join esterno). Inoltre, consente di impostare standard minimi di immissione dei dati, il che è davvero utile.

Ma cosa fai in caso di date, data e ora (SQL Server 2008)? Dovresti usare una data storica o dal basso.

Ciò illustra subito un problema con null, ovvero che un valore memorizzato in una tabella può significare "questo valore non si applica" o "non lo sappiamo". Con le stringhe, una stringa vuota può fungere da "questo non si applica" ma con date e orari non esiste una convenzione del genere perché non esiste un valore valido che convenzionalmente significa questo. In genere lì rimarrai bloccato usando i NULL.

Ci sono modi per aggirare questo problema (aggiungendo più relazioni e unendo) ma quelli pongono esattamente gli stessi problemi di chiarezza semantica che hanno i NULL nel database. Per questi database non me ne preoccuperei. Non c'è proprio niente che tu possa fare al riguardo.

EDIT: un'area in cui i NULL sono indispensabili è nelle chiavi esterne. Qui in genere hanno un solo significato, identico al null nel significato del join esterno. Questa è ovviamente un'eccezione al problema.

10
Chris Travers