web-dev-qa-db-fra.com

Quand utiliser NULL dans les tables MySQL

J'apprécie la signification sémantique d'une valeur NULL dans une table de base de données, différente à la fois de false et de la chaîne vide ''. Cependant, j'ai souvent lu des problèmes de performances lorsque les champs sont nullables et il m'a été conseillé d'utiliser une chaîne vide dans les cas où NULL est en fait sémantiquement correct.

Quelles sont les circonstances appropriées pour utiliser des champs NULL et des valeurs NULL? Quels sont les compromis? Est-il judicieux d'éviter tout simplement d'utiliser des valeurs NULL et d'utiliser simplement des chaînes vides, false ou 0 pour indiquer l'absence d'une valeur?

[~ # ~] mise à jour [~ # ~]

OK - Je comprends la différence sémantique entre "" et NULL ainsi que les circonstances (indépendantes des performances) dans lesquelles NULL est la valeur de champ appropriée. Cependant, permettez-moi de développer le problème de performances évoqué. Ceci est extrait de l'excellent "High Performance MySQL" de Schwartz, Zeitsev et al http://www.borders.co.uk/book/high-performance-mysql-optimization-backups-replication-and-more/ 857673 / :

Il est plus difficile pour MySQL d'optimiser les requêtes qui font référence à des coumns Nullables, car elles compliquent les index, les statistiques d'index et les comparaisons de valeurs. Une colonne Nullable utilise plus d'espace de stockage et nécessite un traitement spécial dans MySQL. Lorsqu'une colonne Nullable est indexée, elle nécessite un octet supplémentaire par entrée et peut même entraîner la conversion d'un index de taille fixe (tel qu'un index sur une seule colonne entière) en un octet de taille variable dans MyISAM.

Plus ici: aperçu de Google livres

C'est très probablement la réponse définitive - je cherchais juste un deuxième avis et une expérience de la première ligne.

48
DavidWinterbottom

Cependant, j'ai souvent lu des problèmes de performances lorsque les champs sont nullables et il m'a été conseillé d'utiliser une chaîne vide dans les cas où NULL est en fait sémantiquement correct.

Je vais être très pointilleux sur le choix de Word pendant un moment:

  • Même si c'était un facteur de performance significatif, cela ne rend pas sémantiquement correct d'utiliser une valeur au lieu de NULL. En SQL, NULL a un rôle sémantique, pour désigner une valeur manquante ou inapplicable. Les caractéristiques de performance de NULL dans une implémentation SGBDR donnée sont indépendantes de cela. Les performances peuvent varier d'une marque à l'autre ou d'une version à l'autre, mais l'objectif de NULL dans la langue est cohérent.

En tout cas, je n'ai entendu parler d'aucune preuve que NULL fonctionne mal. Je serais intéressé par toutes les références aux mesures de performances qui montrent que les colonnes Nullable fonctionnent moins bien que les colonnes non Nullables.

Je ne dis pas que je n'ai pas tort ou que cela ne peut pas être vrai dans certains cas - juste que ce n'est pas significatif de faire de vaines suppositions. La science n'est pas faite de conjectures; il faut montrer des preuves avec des mesures reproductibles.

Les métriques vous indiquent également par combien les performances diffèrent, vous pouvez donc juger si cela vaut la peine de s'inquiéter. Autrement dit, l'impact peut être mesurable et différent de zéro, mais toujours insignifiant par rapport à des facteurs de performances plus élevés, tels que l'indexation correcte des tables ou le dimensionnement de votre cache de base de données.

Dans MySQL, les recherches de NULL peuvent bénéficier d'un index:

mysql> CREATE TABLE foo (
  i INT NOT NULL,
  j INT DEFAULT NULL,
  PRIMARY KEY (i),
  UNIQUE KEY j_index (j)
);

mysql> INSERT INTO foo (i, j) VALUES 
  (1, 1), (2, 2), (3, NULL), (4, NULL), (5, 5);

mysql> EXPLAIN SELECT * FROM foo WHERE i = 3;
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | foo   | const | PRIMARY       | PRIMARY | 4       | const |    1 |       | 
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+

mysql> EXPLAIN SELECT * FROM foo WHERE j IS NULL;
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | foo   | ref  | j_index       | j_index | 5       | const |    2 | Using where | 
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+

Notez que ce n'est toujours pas une mesure de la performance. J'ai seulement montré que vous pouvez utiliser un index lors de la recherche de NULL. Je vais affirmer (certes sans avoir mesuré, mais bon c'est juste StackOverflow) que l'avantage d'un index éclipse toute pénalité possible lors de la recherche de NULL par rapport à une chaîne vide.

Ce n'est pas une décision de conception correcte de choisir zéro ou vide ou toute autre valeur pour remplacer NULL. Vous devrez peut-être utiliser ces valeurs comme significatives dans la colonne. C'est pourquoi NULL existe, en tant que valeur qui est par définition en dehors du domaine des valeurs de tout type de données, de sorte que vous pouvez utiliser la gamme complète de valeurs d'entiers ou de chaînes ou autre et avoir encore quelque chose pour signifier "aucune des valeurs ci-dessus. "

37
Bill Karwin

Le manuel MySQL contient en fait un article sympa sur les problèmes avec NULL.

J'espère que ça aide.

J'ai également trouvé cet autre SO post sur NULL et Performance

11
Ólafur Waage

Nous n'autorisons pas les valeurs NULL dans nos bases de données, sauf pour des valeurs numériques ou pour des dates. La raison pour laquelle nous faisons cela est que les valeurs numériques ne doivent parfois pas être réglées par défaut à zéro car c'est très, très mauvais. Je suis développeur pour un courtier en valeurs mobilières et il y a une grande, grande différence entre NULL et . L'utilisation de COALESCE est pratique si nous voulons ramener les valeurs par défaut à zéro même si nous ne les stockons pas comme telles.

MyVal = COALESCE(TheData, 0)

Comme nous insérons en masse des données à partir de fichiers plats, nous utilisons des fichiers de format pour déterminer l'entrée des données qui convertit automatiquement les valeurs vides en chaînes vides de toute façon.

Les dates par défaut à n'importe quelle valeur qui peut sembler dépendante du classement je crois, mais la nôtre par défaut à quelque chose comme 1900, et encore une fois, les dates sont extrêmement importantes. Les autres valeurs de texte brut ne sont pas si importantes, et si elles sont laissées en blanc, elles sont généralement acceptées.

5
Kezzer

En général, si un attribut est requis, il est défini comme Non NULL et s'il peut être omis, il est défini comme NULL.

3
Jim Anderson

Comme @ForYourOwnGood l'a dit - Null doit être utilisé pour les informations "inconnues". Par exemple: Si vous avez beaucoup de champs que le client doit remplir lors de l'inscription et certains d'entre eux sont facultatifs. Pour une raison quelconque, vous voudrez peut-être réserver un identifiant pour ce client particulier et comme vous ne savez pas si les champs facultatifs sont un véritable choix du client pour être laissés vides, vous devez les définir comme NULL, c'est-à-dire "inconnu" lors de la première sauvegarde la ligne. Si le client soumet le formulaire, passe toute votre validation et que vous enregistrez ensuite les informations, vous savez alors que le champ optionnel est laissé vide par intention.

C'est juste un bon cas d'utilisation de NULL.

2
user1105491

La chaîne vide ne doit pas être utilisée à la place de NULL. NULL ne représente rien là où la chaîne vide est quelque chose, sans rien à l'intérieur. NULL sera toujours faux par rapport à une autre valeur (même NULL) et NULL ne sera pas additionné dans la fonction COUNT.

Si vous avez besoin de représenter des informations inconnues, il n'y a pas de substitut à NULL.

2
ForYourOwnGood

Je comprends qu'il y a des moments où la sémantique NULL de MySQL est tout à fait appropriée.

Cela dit, ils gênent sérieusement, en particulier avec les champs de texte.

Voici un exemple du monde réel.

Nous souhaitons copier les données d'une base de données FileMaker dans une table mysql.

si nous faisons "SELECT * from table where textfield <> 'test'", les lignes qui ont textfield de NULL ne seront PAS retournées. Ce n'est probablement pas ce à quoi vous vous attendiez ou ce que vous souhaitiez.

si un champ qui est nullable est utilisé dans une requête where, seul ou dans le cadre d'un AND, les entrées qui sont NULL ne seront JAMAIS renvoyées à moins que le test IS NULL utilisé. Nous devons faire quelque chose comme "where ((textfield <>" test ") OR (textfield IS NOT NULL))" qui est au mieux moche.

Donc, dans ce cas, nous ne voulons probablement pas que le champ Nullable.

Le problème ici est que vous NE POUVEZ PAS insérer une chaîne vide dans MySQL en utilisant Filemaker. Il est converti en NULL, ce qui entraîne des erreurs si vous avez rendu la colonne non nulle! Si vous autorisez NULL, alors le transfert vers mysql fonctionne, mais vos requêtes not échouent à agir comme vous le souhaitez!

le workaroud consiste à modifier la table deux fois, à convertir les valeurs nulles existantes après l'importation en chaîne vide, puis à modifier la table pour autoriser à nouveau la valeur null. youch!

putain de filemaker.

1
Chuck Cochems

Le principal avantage, bien sûr, est la signification sémantique de NULL, que vous avez mentionnée.

En plus de cela - et cela peut dépendre de votre moteur de stockage, comme toujours, consultez la documentation - mais dans au moins certaines bases de données, les valeurs NULL prennent beaucoup moins de place qu'une valeur normale. Par exemple, si vous avez une colonne "varchar" déclarée comme étant de 20 caractères et qu'elle est rarement remplie, vous pouvez économiser beaucoup d'espace disque en la rendant NULL au lieu d'une chaîne vide.

Je n'ai jamais entendu parler de problèmes de performances liés à l'utilisation de NULL, au contraire. J'ai entendu dire que des gens faisaient leurs comptes parce qu'ils comptaient mal les NULL, mais jamais les performances. Si c'est vrai, j'aimerais en entendre parler!

1
SquareCog

La signification d'une colonne NULL est plus ou moins "ne s'applique pas dans ce contexte". J'utilise généralement des colonnes NULL dans deux cas:

  • Si le champ ne s'applique pas (disons que vous avez une colonne booléenne is_thirsty et que vous ajoutez deux ensembles de données. Un humain et une pierre. Dans le cas de l'humain, vous définissez is_thirsty sur true ou false, alors que dans le cas de la pierre , vous le définiriez probablement sur NULL.
  • Si j'ai besoin de signaler quelque chose et de stocker des données avec la valeur. Comme une date de clôture d'inventaire, que vous utiliseriez pour a) spécifier que l'inventaire ne peut plus être modifié et b) pour spécifier la date de clôture de l'inventaire. Au lieu d'avoir deux colonnes (closed_at et is_closed), Je crée simplement la colonne closed_at et la mets à NULL si l'ensemble d'inventaire peut encore être modifié, mais je fixe la date une fois qu'elle est fermée.

Fondamentalement, cela se résume au fait que j'utilise NULL lorsque le vide d'un champ a une sémantique unique différente de celle d'un champ vide. L'absence d'une initiale du milieu n'est que cela. L'absence de date de clôture signifie que le jeu d'inventaire est toujours ouvert aux modifications.

Les valeurs NULL peuvent avoir des effets secondaires désagréables et vous rendront la vie plus difficile pour ajouter des données à la table et le plus souvent, vous pouvez vous retrouver avec un méli-mélo de valeurs NULL et de chaînes vides par exemple.

De plus, NULL n'est égal à rien, ce qui va visser les requêtes partout si vous ne faites pas très attention.

Personnellement, j'utilise des colonnes NULL uniquement lorsque l'un des deux cas ci-dessus s'applique. Je ne l'utilise jamais pour signifier des champs vides lorsque le vide n'a d'autre sens que l'absence de valeur.

1
pilif

Tout moteur de base de données qui se respecte de nos jours ne devrait offrir aucune pénalité pour une utilisation correcte des NULL, à moins que votre requête ne soit pas conçue correctement (ce qui n'est généralement pas un problème que vous aurez très souvent en ce qui concerne les NULL).

Vous devez d'abord prêter attention à l'utilisation de la base de données (y compris les valeurs NULL) comme prévu; alors s'inquiéter des conséquences de l'optimisation quand et si elles se produisent.

L'effet cumulatif des valeurs de colonne incorrectement NULL en termes de complexité et de précision SQL l'emportera presque sûrement sur les avantages de tromper le SGBD mère. De plus, cela vous gâchera la tête, ainsi que celle de quiconque essaiera plus tard de comprendre ce que vous essayiez de faire.

0
dkretz

Sur certaines bases de données comme Oracle, peut-être que quelque chose sur MySQL est vrai:

  • Les valeurs nulles ne sont pas indexées, alors si la recherche de valeurs nulles peut être un goulot d'étranglement.
  • Les valeurs nulles de fin sur les lignes économisent de l'espace.
0
FerranB