Chaînes en tant que clés primaires dans la base de données SQL


178

Je ne connais pas très bien les bases de données et les théories sur leur fonctionnement. Est-il plus lent du point de vue des performances (insertion / mise à jour / requête) d'utiliser des chaînes pour les clés primaires que des entiers?

Réponses:


191

Techniquement oui, mais si une chaîne a du sens pour être la clé primaire, vous devriez probablement l'utiliser. Tout dépend de la taille de la table pour laquelle vous le créez et de la longueur de la chaîne qui va être la clé primaire (des chaînes plus longues == plus difficiles à comparer). Je n'utiliserais pas nécessairement une chaîne pour une table contenant des millions de lignes, mais le ralentissement des performances que vous obtiendrez en utilisant une chaîne sur des tables plus petites sera minuscule pour les maux de tête que vous pouvez avoir en ayant un entier qui ne le fait pas ça ne veut rien dire par rapport aux données.


11
cela ne dépendrait-il pas de la base de données? Je pense qu'une chaîne correctement indexée ne serait pas beaucoup plus lente, voire pas du tout, à partir d'un nombre?
Ryan Guill

2
Je conviens qu'il y a beaucoup de variables à considérer. (Dans sqlserver), nous avons constaté de réels problèmes de performances lors de l'utilisation de chaînes dont la longueur se situe entre le milieu et le haut et au-dessus, même lorsqu'elles sont indexées. Achetez vous avez raison, il y a des choses pour surmonter ce matériel par exemple.
kemiller2002

1
C'est suffisant. Je conviens cependant que si une chaîne a du sens, c'est ce que vous devriez utiliser. Je dirais aussi qu'il y a certainement des moments pour les champs GUID ou UUID dans les bases de données où un champ d'auto-incrémentation ne fonctionnerait pas.
Ryan Guill

7
Gardez également à l'esprit qu'il y a souvent une très grande différence entre un CHAR et un VARCHAR lors de comparaisons d'index
Tom H

7
Le nombre de commentaires de cette réponse montre clairement à quel point elle est incomplète. Mentionner l'indexation aurait été la réponse minimale acceptable.
Pedro Rolo

74

Un autre problème lié à l'utilisation de chaînes comme clé primaire est que, comme l'index est constamment mis en ordre séquentiel, lorsqu'une nouvelle clé est créée, elle se trouverait au milieu de l'ordre, l'index doit être reséquencé ... si vous utilisez un auto nombre entier, la nouvelle clé est simplement ajoutée à la fin de l'index.


2
Cela peut cependant provoquer des "points chauds" pour les nouveaux inserts. Tant que vous gérez correctement votre base de données, vous devriez avoir de l'espace supplémentaire sur vos pages pour les insertions de toute façon et les fractionnements de page devraient être rares.
Tom H

20
c'est à ce moment que les clés primaires sont mises en cluster. vous pouvez également les créer sans cluster.
Apprentissage du

Les XID sont commandés, ce qui pourrait vous aider si vous utilisez simplement des chaînes
xid

22

Les insertions dans une table ayant un index clusterisé où l'insertion se produit au milieu de la séquence NE provoque PAS la réécriture de l'index. Il n'entraîne pas la réécriture des pages contenant les données. S'il y a de la place sur la page où la ligne ira, elle est placée dans cette page. La page unique sera reformatée pour placer la ligne au bon endroit dans la page. Lorsque la page est pleine, une division de page se produit, la moitié des lignes de la page allant sur une page et la moitié sur l'autre. Les pages sont ensuite reliées à la liste chaînée de pages qui comprennent des données de table qui ont l'index clusterisé. Tout au plus, vous finirez par écrire 2 pages de base de données.


Bonne explication. Mais est-ce vrai pour toutes les bases de données SQL? J'ai entendu parler de problèmes de performances de MySQL lors de l'utilisation d'un UUID aléatoire comme clé primaire.
hgoebl

13

Les chaînes sont plus lentes dans les jointures et dans la vraie vie, elles sont très rarement vraiment uniques (même lorsqu'elles sont censées l'être). Le seul avantage est qu'ils peuvent réduire le nombre de jointures si vous vous joignez à la table principale uniquement pour obtenir le nom. Cependant, les chaînes sont également souvent sujettes à modification, créant ainsi le problème de devoir corriger tous les enregistrements associés lorsque le nom de l'entreprise change ou que la personne se marie. Cela peut être un énorme impact sur les performances et si toutes les tables qui devraient être liées d'une manière ou d'une autre ne sont pas liées (cela se produit plus souvent que vous ne le pensez), vous pourriez également avoir des incohérences de données. Un entier qui ne changera jamais pendant toute la durée de vie de l'enregistrement est un choix beaucoup plus sûr du point de vue de l'intégrité des données ainsi que du point de vue des performances. Les clés naturelles ne sont généralement pas si bonnes pour la maintenance des données.

Je tiens également à souligner que le meilleur des deux mondes est souvent d'utiliser une clé d'auto-incrémentation (ou dans certains cas spécialisés, un GUID) comme PK, puis de mettre un index unique sur la clé naturelle. Vous obtenez les jointures les plus rapides, vous n'obtenez pas d'enregistrements en double et vous n'avez pas à mettre à jour un million d'enregistrements enfants car le nom d'une société a changé.


26
Les chaînes qui sont de bons candidats pour les PK n'ont pas de doublons - sinon elles ne seraient pas un bon candidat pour une PK. Pensez aux codes ICD-9, aux codes de pays, aux numéros VIN. Utiliser un nom comme exemple de problème avec les clés naturelles est malavisé, car ils ne devraient jamais être candidats en premier lieu.
Tom H

6
@Tom H: les codes de comté ISO changent. [ en.wikipedia.org/wiki/ISO_3166-1#Editions_and_changes ] En réponse à une question connexe, [ stackoverflow.com/questions/925266/… ] "Pour les PRIMARY KEY, assurez-vous que leur caractère unique est sous votre contrôle"
Steve Schnepp

4
@SteveSchnepp: oui et l'ISO est l'organisme de confiance pour gérer ce changement. D'un autre côté, lorsque vous devez fusionner votre séquence monotone d'incrémentation de valeurs entières avec celles de quelqu'un d'autre, vous êtes seul;)
quand

1
Je conviens que les noms ne doivent pas être considérés comme une clé, je viens de voir à maintes reprises quand ils l'étaient.
HLGEM

1
@onedayquand la fusion de 2 séquences monotones d'incrémentation d'entiers se fait assez facilement via un préfixe ou un suffixe :)
Steve Schnepp

6

Peu importe ce que vous utilisez comme clé primaire tant qu'elle est UNIQUE. Si vous vous souciez de la vitesse ou de la bonne conception de la base de données, utilisez int sauf si vous prévoyez de répliquer des données, puis utilisez un GUID.

S'il s'agit d'une base de données d'accès ou d'une petite application, qui s'en soucie vraiment. Je pense que la raison pour laquelle la plupart d'entre nous, les développeurs, giflons l'ancien int ou guid à l'avant, c'est parce que les projets ont une façon de grandir sur nous, et vous voulez vous laisser la possibilité de grandir.


5

Trop de variables. Cela dépend de la taille de la table, des index, de la nature de la chaîne clé domaine ...

En général , les entiers seront plus rapides. Mais la différence sera-t-elle assez grande pour s'en soucier? C'est difficile à dire.

Aussi, quelle est votre motivation pour choisir les cordes? Les touches numériques à incrémentation automatique sont souvent beaucoup plus faciles également. Est-ce de la sémantique? Commodité? Problèmes de réplication / déconnectés? Votre réponse ici pourrait limiter vos options. Cela rappelle également une troisième option "hybride" que vous oubliez: les Guids.


cela n'a aucun sens cloutierm, que voulez-vous dire?
HLGEM

@HLGEM: Si je comprends qu'il écrive, il veut dire comme synchroniser des enregistrements créés sur un ordinateur portable avec la base de données principale.
Joel Coehoorn

Je veux dire que j'ai deux bases de données distinctes avec les mêmes entités, une seule est mise à jour moins fréquemment à des fins de stockage persistant. Si je demande l'entité "Californie" sur la base de données A, je veux qu'elle soit fondamentalement la même "Californie" sur la base de données B.
mainstringargs

1
Et c'est «comme» la synchronisation des enregistrements créés dans un ordinateur portable en ce sens que c'est le même problème: les enregistrements créés à un endroit ne doivent pas entrer en conflit avec les enregistrements créés à un autre. Une solution possible ici est les touches Guid.
Joel Coehoorn

5

Ne vous inquiétez pas des performances tant que vous n’avez pas obtenu une conception simple et solide qui correspond au sujet décrit par les données et s’adapte bien à l’utilisation prévue des données. Ensuite, si des problèmes de performances apparaissent, vous pouvez les résoudre en peaufinant le système.

Dans ce cas, il est presque toujours préférable d'utiliser une chaîne comme clé primaire naturelle, à condition que vous puissiez y faire confiance. Ne vous inquiétez pas s'il s'agit d'une chaîne, tant que la chaîne est raisonnablement courte, disons environ 25 caractères maximum. Vous ne paierez pas un gros prix en termes de performances.

Les personnes de saisie de données ou les sources de données automatiques fournissent-elles toujours une valeur pour la clé naturelle supposée ou sont parfois omises? Est-ce parfois erroné dans les données d'entrée? Si oui, comment les erreurs sont-elles détectées et corrigées?

Les programmeurs et les utilisateurs interactifs qui spécifient des requêtes peuvent-ils utiliser la clé naturelle pour obtenir ce qu'ils veulent?

Si vous ne pouvez pas faire confiance à la clé naturelle, inventez un substitut. Si vous inventez un substitut, vous pouvez aussi inventer un entier. Ensuite, vous devez vous soucier de savoir où cacher le substitut à la communauté des utilisateurs. Certains développeurs qui n'ont pas caché la clé de substitution en sont venus à le regretter.


3

Les indices impliquent de nombreuses comparaisons.

En règle générale, les chaînes sont plus longues que les entiers et des règles de classement peuvent être appliquées pour la comparaison, de sorte que la comparaison de chaînes est généralement une tâche plus intensive en calcul que la comparaison d'entiers.

Parfois, cependant, il est plus rapide d'utiliser une chaîne comme clé primaire que de créer une jointure supplémentaire avec une string to numerical idtable.


2

Oui, mais à moins que vous ne vous attendiez à avoir des millions de lignes, ne pas utiliser de clé basée sur une chaîne car elle est plus lente est généralement une «optimisation prématurée». Après tout, les chaînes sont stockées sous forme de grands nombres tandis que les touches numériques sont généralement stockées sous forme de nombres plus petits.

Une chose à surveiller, cependant, est si vous avez des index clusterisés sur une clé any et que vous effectuez un grand nombre d'insertions non séquentielles dans l'index. Chaque ligne écrite entraînera la réécriture de l'index. si vous effectuez des insertions par lots, cela peut vraiment ralentir le processus.


2

Deux raisons d'utiliser des entiers pour les colonnes PK:

  1. Nous pouvons définir l'identité du champ entier qui s'est incrémenté automatiquement.

  2. Lorsque nous créons des PK, la base de données crée un index (Cluster ou Non Cluster) qui trie les données avant qu'elles ne soient stockées dans la table. En utilisant une identité sur un PK, l'optimiseur n'a pas besoin de vérifier l'ordre de tri avant d'enregistrer un enregistrement. Cela améliore les performances sur les grandes tables.


1

Quelle est votre raison d'avoir une chaîne comme clé primaire?

Je voudrais simplement définir la clé primaire sur un champ entier à incrémentation automatique et mettre un index sur le champ de chaîne.

De cette façon, si vous effectuez des recherches sur la table, elles devraient être relativement rapides, et toutes vos jointures et recherches normales ne seront pas affectées par leur vitesse.

Vous pouvez également contrôler la quantité de champ de chaîne qui est indexée. En d'autres termes, vous pouvez dire "indexer uniquement les 5 premiers caractères" si vous pensez que cela suffira. Ou si vos données peuvent être relativement similaires, vous pouvez indexer tout le champ.


3
Je pense que mettre toute intelligence dans une clé pose des problèmes. Vont-ils rester uniques? Ont-ils commencé tous les numéros de compte avec l'abréviation de l'état au début uniquement pour le déplacement du client. Mettre à jour un champ - pas de problème - toutes ces tables liées par numéro de compte - quel bordel.
JeffO

1
Un exemple d'utilisation d'une chaîne comme PK pourrait être une table de paramètres. Par exemple, settingNamePK, isUserEditable, isCustomerEditable etc Ensuite, si vous vouliez modifier le comportement du paramètre "UPDATE setting SET ... WHERE settingNamePK = 'dailyWorkObligation'" est bien plus agréable que d'avoir à utiliser des ID et stocker quelque part le mappage des ID. Bien sûr, vous pouvez avoir un entier PK et avoir le nom du paramètre comme une autre clé unique.
MeatPopsicle

La clé primaire étant un entier auto-incrémenté, les insertions ne devraient-elles pas non plus être affectées par leur vitesse?
Dennis

Pour les développeurs Rails curieux, voici comment spécifier une longueur d'index . Notez que SQLite ne prend pas en charge la longueur d'index.
Dennis

1

Du point de vue des performances - La chaîne Oui (PK) ralentira les performances par rapport aux performances obtenues à l'aide d'un entier (PK), où PK ---> Clé primaire.

Du point de vue des exigences - Bien que cela ne fasse pas partie de votre question, je voudrais encore le mentionner. Lorsque nous traitons d'énormes données sur différentes tables, nous recherchons généralement l'ensemble probable de clés pouvant être définies pour une table particulière. Ceci est principalement dû au fait qu'il existe de nombreuses tables et que la plupart du temps, chacune ou une table serait liée à l'autre par le biais d'une relation (un concept de clé étrangère). Par conséquent, nous ne pouvons vraiment pas toujours choisir un entier comme clé primaire, nous optons plutôt pour une combinaison de 3, 4 ou 5 attributs comme clé primaire pour ces tables. Et ces clés peuvent être utilisées comme clé étrangère lorsque nous relions les enregistrements à une autre table. Cela rend utile de relier les enregistrements entre différentes tables lorsque cela est nécessaire.

Par conséquent, pour une utilisation optimale - Nous faisons toujours une combinaison de 1 ou 2 entiers avec 1 ou 2 attributs de chaîne, mais encore une fois seulement si cela est nécessaire.


0

Il pourrait y avoir un très gros malentendu lié à la chaîne dans la base de données. Presque tout le monde pense que la représentation des nombres dans les bases de données est plus compacte que celle des chaînes. Ils pensent que dans db-s les nombres sont représentés comme dans la mémoire. Mais ce n'est pas vrai. Dans la plupart des cas, la représentation numérique est plus proche de Une chaîne comme représentation que de l'autre.

La vitesse d'utilisation du nombre ou de la chaîne dépend davantage de l'indexation que du type lui-même.


0

Par défaut, ASPNetUserIds contient 128 chaînes de caractères et les performances sont très bien.

Si la clé DOIT être unique dans la table, elle doit être la clé. Voici pourquoi;

clé de chaîne primaire = Corriger les relations de base de données, 1 clé de chaîne (la principale) et 1 chaîne d'index (la principale).

L'autre option est une clé int typique, mais si la chaîne DOIT être unique, vous devrez probablement ajouter un index en raison de requêtes non-stop pour valider ou vérifier qu'il est unique.

Donc, en utilisant une clé d'identité int = relations de base de données incorrectes, 1 clé int (primaire), 1 index int (primaire), probablement un index de chaîne unique et le fait de devoir valider manuellement la même chaîne n'existe pas (quelque chose comme une vérification SQL peut-être ).

Pour obtenir de meilleures performances en utilisant un int sur une chaîne pour la clé primaire, lorsque la chaîne DOIT être unique, cela devrait être une situation très étrange. J'ai toujours préféré utiliser des clés de chaîne. Et en règle générale, ne dénormalisez pas une base de données jusqu'à ce que vous en ayez besoin .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.