Existe-t-il une différence de performances mesurable entre l'utilisation d'INT et de VARCHAR comme clé primaire dans MySQL? Je voudrais utiliser VARCHAR comme clé primaire pour les listes de références (pensez États américains, codes de pays) et un collègue ne bougera pas sur INT AUTO_INCREMENT comme clé primaire pour toutes les tables.
Mon argument, comme détaillé ici , est que la différence de performance entre INT et VARCHAR est négligeable, puisque chaque référence de clé étrangère INT nécessitera un JOIN pour donner un sens à la référence, une clé VARCHAR présentera directement les informations.
Alors, est-ce que quelqu'un a de l'expérience avec ce cas d'utilisation particulier et les problèmes de performances qui y sont associés?
mysql
performance
primary-key
innodb
myisam
Jake McGraw
la source
la source
Réponses:
Vous faites bien valoir que vous pouvez éviter un certain nombre de requêtes jointes en utilisant ce qu'on appelle une clé naturelle au lieu d'une clé de substitution . Vous seul pouvez évaluer si l'avantage de ceci est significatif dans votre application.
Autrement dit, vous pouvez mesurer les requêtes dans votre application qui sont les plus importantes pour être rapides, car elles fonctionnent avec de gros volumes de données ou elles sont exécutées très fréquemment. Si ces requêtes bénéficient de l'élimination d'une jointure et ne souffrent pas de l'utilisation d'une clé primaire varchar, faites-le.
N'utilisez aucune de ces stratégies pour toutes les tables de votre base de données. Il est probable que dans certains cas, une clé naturelle soit meilleure, mais dans d'autres cas, une clé de substitution est meilleure.
D'autres personnes font valoir qu'il est rare dans la pratique qu'une clé naturelle ne change jamais ou ait des doublons, donc les clés de substitution en valent généralement la peine.
la source
Ce n'est pas une question de performance. Il s'agit de ce qui fait une bonne clé primaire. Unique et immuable dans le temps. Vous pensez peut-être qu'une entité telle qu'un code de pays ne change jamais au fil du temps et serait un bon candidat pour une clé primaire. Mais l'expérience amère est que c'est rarement le cas.
INT AUTO_INCREMENT satisfait à la condition "unique et inchangé dans le temps". D'où la préférence.
la source
J'étais un peu ennuyé par le manque de benchmarks pour cela en ligne, alors j'ai moi-même fait un test.
Notez cependant que je ne le fais pas régulièrement, veuillez donc vérifier ma configuration et les étapes pour tout facteur qui aurait pu influencer les résultats involontairement, et poster vos préoccupations dans les commentaires.
La configuration était la suivante:
Les tables:
Ensuite, j'ai rempli 10 millions de lignes dans chaque table avec un script PHP dont l'essence est comme ceci:
Pour les
int
tableaux, le bit a($keys[rand(0, 9)])
été remplacé par justrand(0, 9)
, et pour lesvarchar
tableaux, j'ai utilisé des noms d'états américains complets, sans les couper ou les étendre à 6 caractères.generate_random_string()
génère une chaîne aléatoire de 10 caractères.Ensuite, j'ai couru dans MySQL:
SET SESSION query_cache_type=0;
jan_int
table:SELECT count(*) FROM jan_int WHERE myindex = 5;
SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
myindex = 'califo'
pour leschar
tableaux etmyindex = 'california'
pour lesvarchar
tableaux.Heures de la
BENCHMARK
requête sur chaque table:En ce qui concerne les tailles de table et d'index, voici la sortie de
show table status from janperformancetest;
(avec quelques colonnes non affichées):Ma conclusion est qu'il n'y a pas de différence de performances pour ce cas d'utilisation particulier.
la source
INDEX
placePRIMARY KEY
. Je ne me souviens pas de mon raisonnement - j'ai probablement supposé qu'il s'agissaitPRIMARY KEY
simplement d'uneINDEX
contrainte d'unicité. Cependant, en lisant la section sur la façon dont les choses sont stockées dans InnoDB dans federico-razzoli.com/primary-key-in-innodb , je pense que mes résultats s'appliquent toujours aux clés primaires et répondent à la question sur la différence de performance de recherche de valeur. De plus, votre commentaire suggère d'examiner les performances des algorithmes de tri , qui ne s'appliquent pas au cas d'utilisation que j'étudie, qui recherche des valeurs dans un ensemble.Dépend de la longueur. Si le varchar aura 20 caractères et que l'int est 4, alors si vous utilisez un int, votre index aura CINQ fois plus de nœuds par page d'espace d'index sur le disque ... Cela signifie que traverser l'index nécessitera un cinquième du nombre de lectures physiques et / ou logiques.
Donc, si les performances sont un problème, si vous en avez l'occasion, utilisez toujours une clé intégrale non significative (appelée substitut) pour vos tables et pour les clés étrangères qui référencent les lignes de ces tables ...
Dans le même temps , pour garantir la cohérence des données, chaque table où cela est important doit également avoir une clé alternative non numérique significative (ou un index unique) pour garantir que les lignes dupliquées ne peuvent pas être insérées (duplication basée sur des attributs de table significatifs).
Pour l'utilisation spécifique dont vous parlez (comme les recherches d'état), cela n'a pas vraiment d'importance car la taille de la table est si petite. En général, il n'y a pas d'impact sur les performances des index sur des tables de moins de quelques milliers de lignes. ..
la source
Absolument pas.
J'ai fait plusieurs ... plusieurs ... contrôles de performances entre INT, VARCHAR et CHAR.
La table de 10 millions d'enregistrements avec une CLÉ PRIMAIRE (unique et groupée) avait exactement la même vitesse et les mêmes performances (et le coût de sous-arbre), peu importe laquelle des trois que j'utilisais.
Cela étant dit ... utilisez ce qui est le mieux pour votre application. Ne vous inquiétez pas des performances.
la source
Pour les codes courts, il n'y a probablement aucune différence. Cela est d'autant plus vrai que le tableau contenant ces codes est susceptible d'être très petit (quelques milliers de lignes au maximum) et de ne pas changer souvent (à quand remonte la dernière fois que nous avons ajouté un nouvel État américain).
Pour les tables plus grandes avec une plus grande variation entre les touches, cela peut être dangereux. Pensez à utiliser l'adresse e-mail / le nom d'utilisateur d'une table User, par exemple. Que se passe-t-il lorsque vous avez quelques millions d'utilisateurs et que certains de ces utilisateurs ont des noms longs ou des adresses e-mail. Désormais, chaque fois que vous avez besoin de rejoindre cette table en utilisant cette clé, cela devient beaucoup plus cher.
la source
En ce qui concerne la clé primaire, tout ce qui rend physiquement une ligne unique doit être déterminé comme clé primaire.
Pour une référence en tant que clé étrangère, utiliser un entier à incrémentation automatique comme substitut est une bonne idée pour deux raisons principales.
- Premièrement, il y a généralement moins de frais généraux liés à la jointure.
- Deuxièmement, si vous devez mettre à jour la table qui contient le varchar unique, la mise à jour doit descendre en cascade sur toutes les tables enfants et les mettre à jour toutes ainsi que les index, alors qu'avec le substitut int, il suffit de mettre à jour le table principale et ses index.
L'inconvénient de l'utilisation du substitut est que vous pouvez éventuellement autoriser le changement de la signification du substitut:
Tout dépend de ce dont vous devez vraiment vous soucier dans votre structure et de ce qui signifie le plus.
la source
Cas courants où un substitut
AUTO_INCREMENT
fait mal:Un modèle de schéma commun est un mappage plusieurs-à-plusieurs :
Les performances de ce modèle sont bien meilleures, en particulier lors de l'utilisation d'InnoDB:
Pourquoi?
id
un index.Un autre cas ( pays ):
Trop souvent, le novice normalise country_code en 4 octets
INT
au lieu d'utiliser une chaîne «naturelle» de 2 octets, presque inchangée. Plus rapide, plus petit, moins de JOIN, plus lisible.la source
Chez HauteLook, nous avons changé plusieurs de nos tables pour utiliser des touches naturelles. Nous avons constaté une augmentation réelle des performances. Comme vous l'avez mentionné, beaucoup de nos requêtes utilisent désormais moins de jointures, ce qui les rend plus performantes. Nous utiliserons même une clé primaire composite si cela a du sens. Cela étant dit, certaines tables sont simplement plus faciles à utiliser si elles ont une clé de substitution.
De plus, si vous laissez les gens écrire des interfaces dans votre base de données, une clé de substitution peut être utile. Le tiers peut compter sur le fait que la clé de substitution ne changera que dans de très rares circonstances.
la source
J'ai fait face au même dilemme. J'ai fait un DW (schéma Constellation) avec 3 tableaux de faits, Accidents de la route, Véhicules dans les accidents et Victimes dans les accidents. Les données incluent tous les accidents enregistrés au Royaume-Uni de 1979 à 2012 et 60 tableaux de dimensions. Au total, environ 20 millions de disques.
Relations des tables de faits:
SGBDR: MySQL 5.6
L'index des accidents est nativement un varchar (chiffres et lettres), avec 15 chiffres. J'ai essayé de ne pas avoir de clés de substitution, une fois que les index d'accidents ne changeraient jamais. Dans un ordinateur i7 (8 cœurs), le DW est devenu trop lent à interroger après 12 millions d'enregistrements de charge en fonction des dimensions. Après de nombreuses retouches et l'ajout de clés de substitution bigint, j'ai obtenu une augmentation moyenne des performances de vitesse de 20%. Pourtant, à faible gain de performances, mais essai valable. Je travaille dans le réglage et le clustering de MySQL.
la source
La question concerne MySQL donc je dis qu'il y a une différence significative. S'il s'agissait d'Oracle (qui stocke les nombres sous forme de chaîne - oui, je ne pouvais pas le croire au début) alors pas beaucoup de différence.
Le stockage dans la table n'est pas le problème, mais la mise à jour et la référence à l'index le sont. Les requêtes impliquant la recherche d'un enregistrement en fonction de sa clé primaire sont fréquentes - vous voulez qu'elles se produisent le plus rapidement possible car elles se produisent si souvent.
Le truc, c'est qu'un processeur traite naturellement des entiers de 4 octets et 8 octets, en silicium . Il est VRAIMENT rapide de comparer deux nombres entiers - cela se produit en un ou deux cycles d'horloge.
Maintenant, regardez une chaîne - elle est composée de beaucoup de caractères (plus d'un octet par caractère de nos jours). La comparaison de deux chaînes pour la priorité ne peut pas être effectuée en un ou deux cycles. Au lieu de cela, les caractères des chaînes doivent être itérés jusqu'à ce qu'une différence soit trouvée. Je suis sûr qu'il existe des astuces pour le rendre plus rapide dans certaines bases de données, mais ce n'est pas pertinent ici car une comparaison int se fait naturellement et à une vitesse fulgurante dans le silicium par le processeur.
Ma règle générale - chaque clé primaire devrait être une INT auto-incrémentée, en particulier dans les applications OO utilisant un ORM (Hibernate, Datanucleus, peu importe) où il y a beaucoup de relations entre les objets - elles seront généralement toujours implémentées comme un simple FK et la possibilité DB pour résoudre ces problèmes rapidement est important pour la réactivité de votre application.
la source
Je ne suis pas sûr des implications sur les performances, mais il semble qu'un compromis possible, au moins pendant le développement, consisterait à inclure à la fois la clé de remplacement d'entiers auto-incrémentée, ainsi que la clé «naturelle» unique et prévue. Cela vous donnerait la possibilité d'évaluer les performances, ainsi que d'autres problèmes possibles, y compris la changeabilité des clés naturelles.
la source
Comme d'habitude, il n'y a pas de réponses générales. 'Ça dépend!' et je ne suis pas facétieux. Ma compréhension de la question originale concernait les clés sur de petites tables - comme Country (identifiant entier ou code char / varchar) étant une clé étrangère vers une table potentiellement énorme comme la table d'adresses / contacts.
Il existe deux scénarios ici lorsque vous souhaitez récupérer des données de la base de données. Le premier est un type de requête de type liste / recherche où vous souhaitez répertorier tous les contacts avec des codes ou des noms d'état et de pays (les identifiants n'aideront pas et nécessiteront donc une recherche). L'autre est un scénario d'obtention sur la clé primaire qui montre un enregistrement de contact unique où le nom de l'état, du pays doit être affiché.
Pour ce dernier, peu importe sur quoi le FK est basé puisque nous rassemblons des tables pour un seul enregistrement ou quelques enregistrements et sur des lectures de clés. Le premier scénario (recherche ou liste) peut être impacté par notre choix. Puisqu'il est nécessaire d'afficher le pays (au moins un code reconnaissable et peut-être même la recherche elle-même comprend un code de pays), ne pas avoir à rejoindre une autre table via une clé de substitution peut potentiellement (je suis juste prudent ici car je n'ai pas réellement testé ceci, mais semble hautement probable) améliorer les performances; malgré le fait que cela aide certainement à la recherche.
Comme les codes sont de petite taille - pas plus de 3 caractères généralement pour le pays et l'état, il peut être acceptable d'utiliser les clés naturelles comme clés étrangères dans ce scénario.
L'autre scénario où les clés dépendent de valeurs varchar plus longues et peut-être de tables plus grandes; la clé de substitution a probablement l'avantage.
la source
Permettez-moi de dire oui, il y a certainement une différence, compte tenu de la portée de la performance (définition prête à l'emploi):
1- Utiliser le substitut int est plus rapide en application car vous n'avez pas besoin d'utiliser ToUpper (), ToLower (), ToUpperInvarient () ou ToLowerInvarient () dans votre code ou dans votre requête et ces 4 fonctions ont des benchmarks de performances différents. Consultez les règles de performance de Microsoft à ce sujet. (performance de l'application)
2- L'utilisation de substitut int garantit de ne pas changer la clé au fil du temps. Même les codes de pays peuvent changer, voir Wikipedia comment les codes ISO ont changé au fil du temps. Cela prendrait beaucoup de temps pour changer la clé primaire des sous-arbres. (exécution de la maintenance des données)
3- Il semble qu'il y ait des problèmes avec les solutions ORM, comme NHibernate lorsque PK / FK n'est pas int. (performance du développeur)
la source