J'ai une application (les données sont stockées dans PostgreSQL), où la majorité des champs dans les tables ne sont pas toujours nuls, mais le schéma de ces tables ne les applique pas. Par exemple, regardez cette fausse table:
CREATE TABLE "tbl" (
"id" serial,
"name" varchar(40),
"num" int,
"time" timestamp
PRIMARY KEY ("id"),
UNIQUE ("id")
);
En outre name
, num
, time
ne sont pas explicitement déclaré que NOT NULL
, en réalité , ils sont, parce que l'application se produit du côté de l' application.
Mon sentiment est qu'il devrait être changé, mais le contrepoint est que le niveau d'application s'assure que les valeurs nulles ne peuvent pas apparaître ici et que personne d'autre ne modifie manuellement la table.
Ma question est : quels sont les avantages (performances, stockage, cohérence, autre chose) et inconvénients (en supposant que j'ai déjà vérifié qu'il n'y a pas de null présents pour le moment, et de la logique métier il ne devrait pas y avoir de null) en définissant un NOT NULL
contrainte explicite ?
Nous avons un bon processus de révision du code et une documentation raisonnablement bonne, donc la possibilité qu'une nouvelle personne commette quelque chose qui brise cette contrainte n'est pas vraiment suffisante pour justifier le changement.
Ce n'est pas ma décision, c'est donc exactement pourquoi je cherche d'autres justifications. À mon avis, si quelque chose ne peut pas être nul et qu'une base de données vous permet de spécifier que quelque chose n'est pas nul, alors faites-le. Surtout si le changement est super simple.
la source
NOT NULL
contraintes n'ont aucun effet direct sur la taille du stockage. Bien sûr, toutes les colonnes étant définiesNOT NULL
, il ne peut pas y avoir de bitmap nul au départ. D'un autre côté: la taille de stockage est généralement beaucoup plus petite si vous utilisez NULL au lieu de valeurs "vides" ou factices pour les colonnes sans valeur réelle, car le bitmap nul est comparativement beaucoup plus petit (sauf pour les cas marginaux rares).Réponses:
Que se passe-t-il lorsqu'un nouveau programmeur arrive et doit écrire une application sur cette base de données? Ils ne savent pas que le champ x doit être
NOT NULL
.Un autre programme pourrait supposer que tous les champs x sont
NOT NULL
destinés à effectuer des comptages, mais certains le sont maintenant àNULL
cause du nouveau programme, ce qui entraîne des erreurs incohérentes et difficiles à retracer.À mon humble avis, il est toujours préférable d'appliquer les règles d'intégrité des données aussi près que possible des données, c'est-à-dire dans la base de données. De cette façon, les nouvelles applications et / ou programmeurs ne peuvent pas gâcher vos données.
Les programmeurs, les applications, les langages et les frameworks vont et viennent. Les données et les bases de données ont tendance à persister. La base de données est votre dernière ligne de défense contre les données incohérentes et potentiellement erronées.
Faire un maximum l' utilisation des mécanismes d'application de la contrainte d'intégrité de votre base de données, même au détriment de la performance. Un système lent qui produit des résultats corrects est infiniment supérieur à un système rapide qui se trompe!
la source
IMHO it is always best to enforce data integrity rules as near to the data as possible
c'est en fait le même que le sentiment d'intestin sur lequel j'ai écrit. Et c'est exactement pourquoi je recherche de vraies justifications. Nous avons un examen du code en place et une bonne documentation, donc les inquiétudes concernant un nouveau développeur ne sachant pas quelque chose ne suffisent pas pour justifier le changement.REAL PROGRAMMERS
lu la totalité (ou même n'importe laquelle) de la documentation avant de se retrouver coincés dans un projet où ils se trouvent dans un délai serré?Comme déjà mentionné par d'autres dans les commentaires, l'ajout
NOT NULL
à votre spécification de table peut améliorer de manière significative les performances de vos requêtes (en plus des très bonnes raisons méthodologiques énoncées dans une autre réponse).La raison en est que l'optimiseur de requêtes, sachant qu'une colonne ne peut pas avoir de
NULL
valeur, peut exclure des tests spéciaux pour ces valeurs, comme dans le casNOT IN
vs.NOT EXISTS
Vous pouvez voir par exemple ce blog , où il est montré que ne pas déclarer un champNOT NULL
(lorsque la table contient toujours des valeurs non nulles) avec une certaine requête augmente le temps d'exécution de 500%. Le résultat est affiché pour SQL Server, mais un comportement similaire pourrait être présent dans d'autres SGBD relationnels, comme le vôtre (sans parler du fait que votre base de données pourrait être portée sur d'autres systèmes). Une règle générale que vous pouvez supposer est que lorsque plus d'informations sont disponibles pour l'optimiseur de requête, des plans d'accès plus efficaces peuvent être produits.la source
NOT NULL
pour plusieurs raisons, aucun argument à ce sujet. Mais le lien vers le blog sur SQL Server n'est pas applicable à Postgres et ne prouve aucune des implications de performances que vous mentionnez. Je ne dis pas qu'il n'y en a pas, mais j'aimerais voir des preuves réelles .not in
pour les colonnes nullables est différente, donc il doit y avoir une différence dans le plan entre les deux?Implications spatiales
Les implications spatiales sont discutées dans cet article de @Erwin Brandstetter
En bref, vous économiserez un
totalColumns - 8
bit arrondi à l'octet le plus proche (ouMAXALIGN
), si votre base de données aNOT NULL
Répercussions sur les performances
Cependant, dans ce post sur SE par @Erwin Brandstetter , il dit
@Renzo a une réponse qui parle des implications en termes de performances - je suppose que rien de tout cela n'est applicable à PostgreSQL . Je ne trouve rien qui justifie tout cela comme étant pertinent pour PostgreSQL. Quels que soient les cycles enregistrés, ils ne peuvent pas être quantifiés, même dans la requête la plus rudimentaire.
De plus, j'ai effectué des tests pour voir si les index NULL étaient toujours plus rapides, et je n'ai pas pu le prouver. Vous pouvez trouver ce fil de discussion très utile de Scott Marlowe sur les listes de diffusion qui parle du planificateur de requêtes dans 9.1 étant capable d'utiliser un index partiel sur des clauses WHERE différentes. J'ai testé cela en exécutant ce qui suit
Maintenant, j'ai créé les index,
Dans les deux cas, le planificateur a pu utiliser l'index lors de la sélection pour
= 10
et utilisé un balayage seq lors de la recherche de NULL ou de 0 respectivement. Les deux indices partiels avaient la même taille. Et, les index complets (non représentés) avaient la même taille. En suivant la même méthodologie, j'ai chargé le tableau avec une séquence de1..1e5
, et une valeur null / 0, et une autre séquence de1..1e5
. Les deux méthodes ont pu trouver le null / 0 avec un index couvrant toute la table.TLDR; Résumé
Je ne peux rien prouver d'une manière ou d'une autre sur la plupart des problèmes de performance qui, selon moi, valaient la peine d'être testés pour inclure les insuffisances du planificateur. L'avantage d'utiliser null pour enregistrer ram est réel. L'espace disque économisé en n'utilisant pas null est négligeable, et c'est une surestimation sur les tables avec une
NULLABLE
colonne, ou moins de 8 colonnes. Dans ces cas, aucun espace disque n'est enregistré.la source