Pourquoi l'utilisation des clés de chaîne est-elle généralement considérée comme une mauvaise idée?

24

Cela me dérange depuis un moment. La plupart du temps, lorsqu'il s'agit de stocker des données dans des structures telles que des tables de hachage, des programmeurs, des livres et des articles insistent sur le fait que l'indexation des éléments dans ces structures par des valeurs de chaîne est considérée comme une mauvaise pratique. Pourtant, jusqu'à présent, je n'ai pas trouvé une seule source de ce type pour expliquer également POURQUOI elle est considérée comme une mauvaise pratique. Cela dépend-il du langage de programmation? Sur le cadre sous-jacent? Sur la mise en œuvre?

Prenez deux exemples simples, si cela vous aide:

Une table de type SQL où les lignes sont indexées par une clé primaire String.

Un dictionnaire .NET où les clés sont des chaînes.


la source
9
Avoir des clés de chaîne n'est pas une mauvaise idée en général. Je soupçonne que ces déclarations ont été faites dans un contexte où un meilleur type de clé est disponible. J'ai des dictionnaires .net avec des clés de chaîne tout le temps. Pouvez-vous donner quelques exemples de cette affirmation?
CodesInChaos
3
Vous voulez généralement des clés primaires qui ne changent pas pendant la durée de vie d'un objet / d'une ligne. Ainsi, par exemple username, la clé primaire d'une userstable n'est probablement pas la meilleure idée, et vous préféreriez un identifiant d'incrémentation automatique. Mais c'est usernameune chaîne n'est qu'accessoire, être une propriété mutable est le principal problème
CodesInChaos
Dans une base de données, examinez comment indexerait des chaînes par opposition aux entiers.
@CodesInChaos J'aimerais pouvoir me rappeler où j'ai trouvé la plupart des cas, mais pour l'instant je peux coller le morceau qui m'a rappelé le problème. C'était à partir d'un diaporama GDC par Valve qui a discuté des dialogues de jeu et du stockage des faits sur le monde dans des paires <key = string, value = object>.
2
Les cordes vont bien. Pas des cordes «magiques». Donc, lorsque vous utilisez une table de hachage, assurez-vous de ne pas avoir de chaînes nues dans votre code. Vous devez éviter les grandes valeurs de texte comme clés car elles ne fonctionnent pas bien, mais dans la plupart des situations du monde réel, une courte chaîne de texte est aussi rapide qu'un entier (ce ne sont pas des bases de données massives). Vous pouvez également utiliser des clés alternatives, par exemple, la clé primaire est un nombre, mais il existe également une `` slug '' ou une chaîne unique qui est également unique.
ipaul

Réponses:

17

Tout cela a à voir avec les deux choses essentiellement:

1) La vitesse de recherche (où les entiers, par exemple, se portent beaucoup mieux)

2) La taille des index (où les index de chaîne exploseraient)

Maintenant, tout dépend de vos besoins et de la taille de l'ensemble de données. Si une table ou une collection contient 10 à 20 éléments, le type de clé n'est pas pertinent. Ce sera très rapide même avec une clé de chaîne.

PS Peut ne pas être lié à votre question, mais les guides sont également considérés comme mauvais pour les clés de base de données (Guid de 16 octets contre un entier de 4 octets). Sur les gros volumes de données, les GUID ralentissent la recherche.

lapin
la source
Pas toujours - des GUID incrémentiels sont possibles. Les index seront toujours plus gros, mais la pénalité de recherche ne sera pas aussi mauvaise.
Sam
7
En fait, ils vont bien. Vous devez examiner la relation entre le temps IO du disque de temps et la comparaison des valeurs en mémoire. Étant donné que les temps d'accès au disque dépassent la comparaison de la mémoire, la seule chose qui compte vraiment dans l'analyse des performances de la base de données est l'IO. Que la clé soit un GUID, une chaîne ou un entier n'est pas vraiment critique. La taille de l'index affecte le nombre de valeurs d'index pouvant tenir sur une page, mais le fait que la clé soit un entier de 4 octets (qui peut ne pas être assez grand et ne peut pas être généré par le client) ou une valeur de 16 octets n'est pas un problème majeur. Dans certaines bases de données, les rowId peuvent avoir une taille de 16 octets.
ipaul
9

Il y a un autre problème avec l'utilisation de chaînes comme clés, ou plus précisément, l'utilisation de littéraux de chaîne comme clés, en mettant de côté des raisons de performances / efficacité pures. Typos. Si vous utilisez des littéraux de chaîne comme clés dans un dictionnaire, vous vous préparez à une mauvaise surprise quand on "ReceiverId"devient un "RecieverId". Configurez des constantes pour stocker les valeurs clés et réutilisez-les chaque fois que vous accédez au dictionnaire.

Trivial et évident, vous pouvez dire, mais un nombre étonnant d'exemples de code .NET sur le Web utilise des littéraux de chaîne, propageant cette pratique douteuse. ASP.NET avec toutes les sessions, ViewStates et QueryParams disséminés à travers la base de code est particulièrement coupable ici.

scrwtp
la source
IMHO pas trivial. J'ai également vu des cas où il y a des clés "1"et "1 "dans la même table.
pswg
Soyez encore plus amusant lorsque vous ajoutez la sensibilité à la casse dans le mélange. J'ai vu des tas de gens, dont moi, tomber directement sur celui-là.
Tony Hopkinson
Encore mieux que d'utiliser des constantes, en C # au moins, utilisez plutôt des expressions. De cette façon, vous pouvez générer vos chaînes à partir des noms des méthodes / propriétés, etc. afin que vos recherches de chaînes deviennent sûres pour les types et faciles à modifier.
GoatInTheMachine
4

Il y a de nombreux compromis ici. En fait, j'utilise fréquemment des clés de chaîne, mais j'inclus souvent des clés secondaires de substitution pour les jointures (ce serait évidemment l'inverse si j'utilisais MySQL). Il y a des cas où je n'en ai pas cependant.

Tout d'abord, je suis un fan de déclarer les clés naturelles comme la clé primaire où la base de données peut bien gérer cela (PostgreSQL par exemple). Cela aide à la normalisation et permet une conception plus claire de la base de données. Les touches de substitution facilitent la connexion.

Il y a deux raisons pour lesquelles j'ajoute généralement des clés de substitution:

  1. On ne sait pas toujours ce qu'est une clé naturelle. Parfois, ceux-ci doivent être modifiés. Changer une clé composite naturelle lorsqu'elle est utilisée pour les jointures et l'intégrité référentielle est compliqué et sujet aux erreurs.

  2. Les performances de jointure sur les clés composites sont problématiques et une fois que vous suivez la route des clés naturelles, vous y êtes coincé.

Dans les cas où une clé naturelle est une définition, une seule colonne et du texte, cependant, je joins généralement la clé de chaîne. Ma raison est que cela évite souvent les jointures lors de la recherche. L'utilisation la plus courante consiste à fournir une conception de base de données appropriée autour du cas d'utilisation des types d'énumération. Dans la plupart des cas, ceux-ci ne nécessitent pas la jointure supplémentaire pour les requêtes de routine. Donc, lorsque c'est le cas, les clés de chaîne en tant que clés de jointure ont un sens parfait.

Par exemple, dans LedgerSMB, nous stockons les catégorisations de compte. Celles-ci sont identifiées par une référence de chaîne et d'autres données sont stockées avec la référence de chaîne qui est utilisée pour appliquer les règles concernant les combinaisons de catégorisations qui peuvent affecter un compte. La seule fois où la logique est nécessaire est lors de l'enregistrement d'un ensemble de catégorisations, nous nous joignons donc à la clé de chaîne.

Quant à savoir pourquoi la valeur par défaut serait des clés entières, je ne pense pas que ce soit juste une question de taille d'index. Un gros problème est la gestion des clés. Étant donné que la clé est arbitraire et que vous pouvez avoir affaire à des millions d'enregistrements, vous devez avoir un moyen de générer des chaînes uniques. Il y a des cas où les gens utilisent des UUID pour cela, mais il y a une chance non nulle de collision UUID, et où des milliards d'enregistrements sont stockés, cette chance devient suffisamment élevée que l'on pourrait réellement voir tandis que la probabilité de collision avec des types entiers incrémentés est nulle par définition.

Chris Travers
la source
Ce n'est pas différent de zéro si vous parvenez à remettre le type entier à zéro. Pour un type 32 bits non signé, qui n'est qu'à 4G, ce qui est étrangement proche avec des "milliards d'enregistrements"…
Donal Fellows
Si vous avez une base de données que vous pouvez dire "erreur plutôt que de boucler", elle est nulle. En tout cas, il est plus facile de gérer la possibilité de collision avec des nombres entiers incrémentaux qu'avec des valeurs pseudo-aléatoires.
Chris Travers
1

Il existe un certain nombre de problèmes potentiels liés à l'utilisation de chaînes comme clés, en particulier lorsqu'il s'agit de tables de type SQL. Comme mentionné par @bunny, les index de vos tables vont être plus grands, mais je pense que plus important encore, toute relation de clé étrangère avec la table impliquera que les deux tables contiennent la chaîne par opposition à un identificateur plus léger (entier) . Si vous trouvez qu'il y a encore plus de tables avec des références à la première, les clés de chaîne se multiplieront dans votre base de données.

Matthew Flynn
la source
1

Ce n'est pas une mauvaise idée en soi, c'est généralement avec un recul de 20/20 un mauvais compromis de conception. La flexibilité et la gamme de cordes par rapport au coût et à la complexité supplémentaires.

Si l'entier fait la plage de travaux et que la majeure partie du traitement coûteux n'a pas besoin de savoir ce que l'entier représente, utilisez-en un.

Tony Hopkinson
la source
0

Vous avez en quelque sorte récupéré les mauvaises données d'une table de hachage.

Voulez-vous dire "DaytimeTelephone" ou "EveningTelephone"?

ou

Voulez-vous dire 1234567 ou 1234576?

Alors que les chiffres sont sans doute plus efficaces pour la machine , chaque fois que les choses tournent mal (et ils le font), il revient à vous et à moi de comprendre ce qui s'est passé et, à ce stade, d'économiser quelques octets de stockage et quelques micro (nano?) - les secondes de traitement perdent en clarté à chaque fois.

Phill W.
la source
1
Et ainsi vous vous retrouvez avec une liste de constantes, en utilisant le nom de la constante dans votre code pour représenter le nombre magique ... Java énumère à la rescousse pour l'abstraire encore plus loin et vous laisse avec juste le nom et ayant l'ordinal cartographie invisible.
jwenting
-1

Beaucoup de compromis et pas de bonne réponse. De nombreux programmeurs n'envisageraient jamais d'utiliser des clés de chaîne dans la base de données car ils ne connaissent pas le hachage et le fonctionnement d'une base de données. Les clés de chaîne tant qu'elles sont extrêmement stables ou sans signification (substituts) sont un bon choix de conception dans de nombreuses circonstances.

moss23
la source
2
Cette réponse n'ajoute rien qui n'ait déjà été dit dans les autres réponses, qui le disent mieux.
Martijn Pieters
-2

la clé de chaîne aura un sens, lorsqu'il s'agit d'une table de recherche avec environ 10 à 100 enregistrements de chaîne courts; les données associées sont plus lisibles + par exemple, le suivi des modifications (identifiant numérique / guid vs chaîne par exemple "Administrateur"); btw, la base de données des membres ASP.NET utilise des clés de chaîne pour AspNetRoles.

Alfred Hitchcock
la source