web-dev-qa-db-fra.com

Pourquoi ne devrions-nous pas autoriser les valeurs NULL?

Je me souviens avoir lu cet article sur la conception de bases de données et je me souviens aussi qu'il disait que vous devriez avoir des propriétés de champ NOT NULL. Je ne me souviens pas pourquoi c'était le cas cependant.

Tout ce à quoi je peux penser, c'est qu'en tant que développeur d'applications, vous n'auriez pas à tester NULL et une possible valeur de données inexistante (par exemple, une chaîne vide pour les chaînes).

Mais que faites-vous dans le cas des dates, datetime et heure (SQL Server 2008)? Vous devez utiliser une date historique ou un creux.

Des idées à ce sujet?

127
Thomas Stringer

Je pense que la question est mal formulée, car le libellé implique que vous avez déjà décidé que les valeurs NULL sont mauvaises. Peut-être que vous vouliez dire "Devrions-nous autoriser les valeurs NULL?"

Quoi qu'il en soit, voici mon point de vue: je pense que les NULLs sont une bonne chose. Lorsque vous commencez à empêcher les valeurs NULL simplement parce que "les valeurs NULL sont mauvaises" ou "les valeurs NULL sont difficiles", vous commencez à créer des données. Par exemple, que faire si vous ne connaissez pas ma date de naissance? Qu'allez-vous mettre dans la colonne jusqu'à ce que vous sachiez? Si vous ressemblez à beaucoup de gens anti-NULL, vous allez entrer 1900-01-01. Maintenant, je vais être placé dans le service de gériatrie et probablement recevoir un appel de ma station de nouvelles locale me félicitant pour ma longue vie, me demandant mes secrets pour vivre une si longue vie, etc.

Si une ligne peut être entrée là où il est possible que vous ne connaissiez pas la valeur d'une colonne, je pense que NULL est beaucoup plus logique que de choisir une valeur de jeton arbitraire pour représenter le fait qu'elle est inconnue - une valeur que d'autres devront déjà connaître, procéder à une ingénierie inverse ou demander aux alentours de comprendre ce que cela signifie.

Il y a cependant un équilibre - toutes les colonnes de votre modèle de données ne doivent pas être annulables. Il y a souvent des champs facultatifs sur un formulaire ou des informations qui autrement ne sont pas collectées au moment de la création de la ligne. Mais cela ne signifie pas que vous pouvez différer le remplissage de toutes les données . :-)

La capacité à utiliser NULL peut également être limitée par des exigences cruciales dans la vie réelle. Dans le domaine médical, par exemple, il peut s'agir d'une question de vie ou de mort de savoir pourquoi une valeur est inconnue. Le rythme cardiaque est-il NUL parce qu'il n'y a pas eu de pouls ou parce que nous ne l'avons pas encore mesuré? Dans un tel cas, pouvons-nous mettre NULL dans la colonne de fréquence cardiaque et avoir des notes ou une colonne différente avec une raison NULL parce que?

N'ayez pas peur des NULL, mais soyez prêt à apprendre ou à dicter quand et où ils devraient être utilisés, et quand et où ils ne devraient pas.

232
Aaron Bertrand

Les raisons établies sont:

  • NULL n'est pas une valeur et n'a donc pas de type de données intrinsèque. Les Nulls nécessitent une gestion spéciale partout lorsque le code qui s'appuie autrement sur des types réels peut également recevoir le NULL non typé.

  • NULL rompt la logique à deux valeurs (familier Vrai ou Faux) et nécessite une logique à trois valeurs. Ceci est beaucoup plus complexe à implémenter même correctement, et est certainement mal compris par la plupart des DBA et à peu près tous les non-DBA. En conséquence, il invite positivement de nombreux bugs subtils dans l'application.

  • La signification sémantique de tout NULL spécifique est laissée à l'application , contrairement aux valeurs réelles.

    Les sémantiques comme "sans objet" et "inconnu" et "sentinelle" sont courantes, et il y en a d'autres également. Ils sont fréquemment utilisés simultanément dans la même base de données, même dans la même relation; et sont bien sûr des significations inexplicables et indiscernables et incompatibles .

  • Ils ne sont pas nécessaires aux bases de données relationnelles , comme indiqué dans "Comment gérer les informations manquantes sans Nulls" . Une normalisation plus poussée est une première étape évidente pour essayer de débarrasser une table de NULL.

Cela ne signifie pas que NULL ne devrait jamais être autorisé. Il le fait soutiennent qu'il existe de nombreuses bonnes raisons de refuser NULL dans la mesure du possible.

De manière significative, il plaide pour essayer très fort - grâce à une meilleure conception de schéma, et de meilleurs moteurs de base de données, et même de meilleurs langages de base de données - pour faire il est possible d'éviter NULL plus souvent.

Fabian Pascal répond à un certain nombre d'arguments, dans "Nulls Nullified" .

61
bignose

Je ne suis pas d'accord, les null sont un élément essentiel de la conception d'une base de données. L'alternative, comme vous l'avez également mentionné, serait une prolifération de valeurs connues pour représenter les disparus ou les inconnus. Le problème réside dans le fait que null est si mal compris et, par conséquent, utilisé de manière inappropriée.

IIRC, Codd a suggéré que la mise en œuvre actuelle de null (ce qui signifie non présent/manquant) pourrait être améliorée en ayant deux marqueurs null plutôt qu'un, "non présent mais applicable" et "non présent et non applicable". Je ne peux pas imaginer comment les conceptions relationnelles pourraient être améliorées par cela personnellement.

32
Mark Storey-Smith

Permettez-moi de commencer en disant que je ne suis pas un DBA, je suis un développeur par cœur et je maintiens et met à jour nos bases de données en fonction de nos besoins. Cela étant dit, j'avais la même question pour plusieurs raisons.

  1. Les valeurs nulles rendent le développement plus difficile et sujet aux bogues.
  2. Les valeurs nulles rendent les requêtes, les procédures stockées et les vues plus complexes et sujettes aux bogues.
  3. Les valeurs nulles occupent de l'espace (? Octets basés sur une longueur de colonne fixe ou 2 octets pour une longueur de colonne variable).
  4. Les valeurs nulles peuvent affecter souvent l'indexation et les mathématiques.

Je passe très longtemps à parcourir les nombreuses réponses, commentaires, articles et conseils sur Internet. Inutile de dire que la plupart des informations étaient à peu près les mêmes que la réponse de @ AaronBertrand. C'est pourquoi j'ai ressenti le besoin de répondre à cette question.

Tout d'abord, je veux définir quelque chose de direct pour tous les futurs lecteurs ... Les valeurs NULL représentent des données inconnues PAS des données inutilisées. Si vous avez une table des employés qui a un champ de date de fin. Une valeur nulle dans la date de fin est due au fait qu'il s'agit d'un futur champ obligatoire qui est actuellement inconnu. Chaque employé, qu'il soit actif ou licencié, aura à un moment donné une date ajoutée à ce champ. C'est à mon avis la seule et unique raison pour un champ Nullable.

Cela étant dit, la même table des employés contiendrait probablement une sorte de données d'authentification. Il est courant dans un environnement d'entreprise que les employés soient répertoriés dans la base de données pour les RH et la comptabilité, mais n'ont pas toujours ou n'ont pas besoin de détails d'authentification. La plupart des réponses vous amèneraient à penser qu'il est correct d'annuler ces champs ou, dans certains cas, de leur créer un compte, mais de ne jamais leur envoyer les informations d'identification. Le premier amènera votre équipe de développement à écrire du code pour vérifier les NULL et à les traiter en conséquence, et le second pose un énorme risque pour la sécurité! Les comptes qui ne sont pas encore utilisés dans le système augmentent uniquement le nombre de points d'accès possibles pour un pirate informatique, et ils occupent un espace de base de données précieux pour quelque chose qui n'est jamais utilisé.

Compte tenu des informations ci-dessus, la meilleure façon de traiter les données annulables qui SERONT utilisées est d'autoriser les valeurs annulables. C'est triste mais vrai et vos développeurs vous détesteront pour cela. Le deuxième type de données annulables doit être placé dans une table associée (IE: compte, informations d'identification, etc.) et avoir une relation un à un. Cela permet à un utilisateur d'exister sans informations d'identification, sauf si elles sont nécessaires. Cela supprime le risque de sécurité supplémentaire, l'espace de base de données précieux et fournit une base de données beaucoup plus propre.

Vous trouverez ci-dessous une structure de tableau très simpliste montrant à la fois la colonne nullable requise et une relation un à un.

Unknown Nullable and One-to-One relationship

Je sais que je suis un peu en retard au parti depuis que cette question a été posée il y a des années, mais j'espère que cela aidera à faire la lumière sur cette question et sur la meilleure façon de la résoudre.

14
Nicholas Aguirre

Mis à part tous les problèmes avec les développeurs déroutants NULL, les NULL ont un autre inconvénient très sérieux: les performances

Les colonnes NULL sont un désastre du point de vue des performances. Considérez l'arithmétique des entiers comme exemple. Dans un monde sain sans NULL, il est "facile" de vectoriser l'arithmétique entière dans le code du moteur de base de données en utilisant les instructions SIMD pour effectuer à peu près n'importe quel calcul à des vitesses plus rapides que 1 ligne par cycle de CPU. Cependant, au moment où vous introduisez NULL, vous devez gérer tous les cas spéciaux créés par NULL. Les jeux d'instructions CPU modernes (lire: x86/x64/ARM et logique GPU aussi) ne sont tout simplement pas équipés pour le faire efficacement.

Considérez la division comme exemple. À un niveau très élevé, c'est la logique dont vous avez besoin avec un entier non nul:

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

Avec NULL, cela devient un peu plus délicat. Avec b, vous aurez besoin d'un indicateur si b est nul et de même pour a. Le chèque devient maintenant:

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'arithmétique NULL est beaucoup plus lente à fonctionner sur un processeur moderne que l'arithmétique non nulle (par un facteur d'environ 2-3x).

Cela empire lorsque vous introduisez SIMD. Avec SIMD, un processeur Intel moderne peut effectuer 4 divisions entières de 32 bits en une seule instruction, comme ceci:

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

Maintenant, il existe également des moyens de gérer NULL dans le pays SIMD, mais cela nécessite l'utilisation de plus de vecteurs et de registres CPU et un masquage intelligent des bits. Même avec de bonnes astuces, la pénalité de performance de l'arithmétique entière NULL se glisse dans la plage 5-10x plus lente pour des expressions même relativement simples.

Quelque chose comme ce qui précède vaut pour les agrégats et dans une certaine mesure, pour les jointures aussi.

En d'autres termes: L'existence de NULL dans SQL est un décalage d'impédance entre la théorie de la base de données et la conception réelle des ordinateurs modernes. Il y a une bonne raison pour laquelle NULL confond les développeurs - car un entier ne peut pas être NULL dans la plupart des langages de programmation sensés - ce n'est tout simplement pas ainsi que les ordinateurs fonctionnent.

13
Thomas Kejser

article de Wikipedia sur SQL Null a quelques remarques intéressantes sur la valeur NULL, et en tant que réponse indépendante de la base de données, tant que vous êtes conscient des effets potentiels d'avoir des valeurs NULL pour votre SGBDR spécifique, ils sont acceptable dans votre conception. Si ce n'était pas le cas, vous ne seriez pas en mesure de spécifier des colonnes comme nullables.

Sachez simplement comment votre SGBDR les gère dans les opérations SELECT telles que les mathématiques, ainsi que dans les index.

10
Derek Downey

Questions intéressantes.

Tout ce à quoi je peux penser, c'est qu'en tant que développeur d'application, vous n'auriez pas à tester NULL et une éventuelle valeur de données inexistante (par exemple, une chaîne vide pour les chaînes).

C'est plus compliqué que ça. Null a un certain nombre de significations distinctes et une raison vraiment importante de ne pas autoriser les valeurs nulles dans de nombreuses colonnes est que lorsque la colonne est nulle, cela signifie une et une seule chose (à savoir qu'elle ne s'est pas affichée dans une jointure externe). De plus, il vous permet de définir des normes minimales de saisie de données, ce qui est vraiment utile.

Mais que faites-vous dans le cas des dates, datetime et heure (SQL Server 2008)? Vous devez utiliser une date historique ou un creux.

Cela illustre tout de suite un problème avec les valeurs nulles, à savoir qu'une valeur stockée dans une table peut signifier "cette valeur ne s'applique pas" ou "nous ne savons pas". Avec les chaînes, une chaîne vide peut servir de "cela ne s'applique pas" mais avec les dates et les heures, il n'y a pas de convention de ce type car il n'y a pas de valeur valide qui signifie conventionnellement cela. En règle générale, vous serez bloqué en utilisant des valeurs NULL.

Il existe des moyens de contourner cela (en ajoutant plus de relations et en se joignant), mais ceux-ci posent exactement les mêmes problèmes de clarté sémantique que les NULL dans la base de données. Pour ces bases de données, je ne m'en inquiéterais pas. Il n'y a vraiment rien que vous puissiez faire à ce sujet.

EDIT: Un domaine où les NULLs sont indispensables est dans les clés étrangères. Ici, ils n'ont généralement qu'une seule signification, identique à la valeur null dans la signification de jointure externe. C'est une exception au problème bien sûr.

10
Chris Travers