Existe-t-il une réelle différence de performances entre les clés primaires INT et VARCHAR?

174

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?

Jake McGraw
la source
3
J'ai fait un post avec la réponse "non" avec quelques détails des tests que j'ai exécutés ... mais c'était SQL Server, pas MySQL. J'ai donc supprimé ma réponse.
Timothy Khouri
17
@Timothy - vous n'auriez pas dû le supprimer. J'étais en train de voter. La plupart des serveurs de base de données SQL ont des planificateurs de requêtes similaires et des goulots d'étranglement de performances similaires.
Paul Tomblin
9
@Timothy s'il vous plaît republiez vos résultats.
Jake McGraw
2
Tant de commentaires et de réponses supposent que les clés sont là pour être utilisées pour les jointures. Ils ne sont pas. Les clés sont là pour être utilisées pour la cohérence des données - pour éviter les lignes en double, (plus d'une ligne représentant la même entité). Toute colonne (ou ensemble de colonnes) peut être utilisée dans une jointure, et pour garantir que la jointure est un à zéro ou plusieurs, la ou les colonnes doivent simplement être uniques. Tout index unique garantit cela, et il n'a pas besoin d'être significatif.
Charles Bretana

Réponses:

78

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.

Bill Karwin
la source
3
Et parfois, (à mon humble avis, souvent), les deux sont meilleurs, le substitut à utiliser pour les références FK dans d'autres tables et pour les jointures, et la clé naturelle pour assurer la cohérence des données
Charles Bretana
@CharlesBretana C'est intéressant. L'utilisation d'une clé naturelle pour la cohérence des données parallèlement au FK est-elle une pratique courante? Ma première pensée a été que le stockage supplémentaire qui serait nécessaire sur de grandes tables pourrait ne pas en valoir la peine. Toute information est appréciée. FYI - J'ai une expérience de programmation décente mais mon expérience SQL se limite principalement aux requêtes SELECT
Rob
2
@CharlesBretana Quand je lis "stockez-les tous les deux", je pense que "redondance" et "non normalisé", ce qui équivaut à "ce truc pourrait être foutu" et "je dois m'assurer que les deux sont changés si jamais l'un est changé". Si vous avez une redondance, il devrait y avoir une très bonne raison (comme des performances totalement inacceptables) car la redondance est toujours susceptible de rendre vos données incohérentes.
jpmc26
3
@ jpmc26, Il n'y a absolument AUCUN problème de redondance ou de normalisation impliqué. Une clé de substitution n'a pas de connexion significative avec les valeurs d'une clé naturelle, elle ne devrait donc jamais avoir besoin d'être modifiée. Quant à la normalisation, de quels problèmes de normalisation parlez-vous? La normalisation s'applique aux attributs significatifs d'une relation; la valeur numérique d'une clé de substitution (en fait, le concept même d'une clé de substitution lui-même) se situe complètement en dehors du contexte de toute normalisation.
Charles Bretana
1
Et pour répondre à votre autre question, en particulier sur une table d'états, si vous aviez une clé de substitution sur cette table, avec des valeurs, disons, de 1 à 50, mais que vous n'avez PAS mis un autre index ou clé unique sur le code postal de l'état, (et, à mon avis, sur le nom de l'état également), alors qu'est-ce qui empêche quelqu'un d'entrer deux lignes avec des valeurs de clé de substitution différentes mais avec le même code postal et / ou le même nom d'état? Comment l'application cliente le gérerait-elle s'il y avait deux lignes avec «NJ», «New Jersey»? Les clés naturelles assurent la cohérence des données!
Charles Bretana
81

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.

Steve McLeod
la source
25
Vrai. L'une de mes plus grandes bases de données contient des entrées pour la Yougoslavie et l'Union soviétique. Je suis content qu'il ne s'agisse pas de clés primaires.
Paul Tomblin
8
@Steve, alors pourquoi ANSI SQL prend-il en charge la syntaxe pour ON UPDATE CASCADE?
Bill Karwin
5
L'immuabilité n'est pas une exigence d'une clé. Dans tous les cas, les clés de substitution changent parfois aussi. Rien de mal à changer de clé si vous en avez besoin.
nvogel
9
Paul, alors vous avez changé l'Union soviétique en Russie dans votre base de données? Et faire semblant que SU n'existe jamais? Et toutes les références à la SU pointent désormais vers la Russie?
Dainius
6
@alga Je suis né en SU ​​alors je sais ce que c'est.
Dainius
52

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:

  • Processeur Intel® Core ™ i7-7500U à 2,70 GHz × 4
  • 15,6 Gio de RAM, dont je me suis assuré que 8 Go environ étaient libres pendant le test.
  • Disque SSD de 148,6 Go, avec beaucoup d'espace libre.
  • Ubuntu 16.04 64 bits
  • MySQL Ver 14.14 Distrib 5.7.20, pour Linux (x86_64)

Les tables:

create table jan_int (data1 varchar(255), data2 int(10), myindex tinyint(4)) ENGINE=InnoDB;
create table jan_int_index (data1 varchar(255), data2 int(10), myindex tinyint(4), INDEX (myindex)) ENGINE=InnoDB;
create table jan_char (data1 varchar(255), data2 int(10), myindex char(6)) ENGINE=InnoDB;
create table jan_char_index (data1 varchar(255), data2 int(10), myindex char(6), INDEX (myindex)) ENGINE=InnoDB;
create table jan_varchar (data1 varchar(255), data2 int(10), myindex varchar(63)) ENGINE=InnoDB;
create table jan_varchar_index (data1 varchar(255), data2 int(10), myindex varchar(63), INDEX (myindex)) ENGINE=InnoDB;

Ensuite, j'ai rempli 10 millions de lignes dans chaque table avec un script PHP dont l'essence est comme ceci:

$pdo = get_pdo();

$keys = [ 'alabam', 'massac', 'newyor', 'newham', 'delawa', 'califo', 'nevada', 'texas_', 'florid', 'ohio__' ];

for ($k = 0; $k < 10; $k++) {
    for ($j = 0; $j < 1000; $j++) {
        $val = '';
        for ($i = 0; $i < 1000; $i++) {
            $val .= '("' . generate_random_string() . '", ' . rand (0, 10000) . ', "' . ($keys[rand(0, 9)]) . '"),';
        }
        $val = rtrim($val, ',');
        $pdo->query('INSERT INTO jan_char VALUES ' . $val);
    }
    echo "\n" . ($k + 1) . ' millon(s) rows inserted.';
}

Pour les inttableaux, le bit a ($keys[rand(0, 9)])été remplacé par just rand(0, 9), et pour les varchartableaux, 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;
  • Pour la jan_inttable:
    • SELECT count(*) FROM jan_int WHERE myindex = 5;
    • SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
  • Pour les autres tableaux, comme ci-dessus, avec myindex = 'califo'pour les chartableaux et myindex = 'california'pour les varchartableaux.

Heures de la BENCHMARKrequête sur chaque table:

  • jan_int: 21,30 s
  • jan_int_index: 18,79 secondes
  • jan_char: 21,70 s
  • jan_char_index: 18,85 s
  • jan_varchar: 21,76 s
  • jan_varchar_index: 18,86 s

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):

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Name              | Engine | Version | Row_format | Rows    | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Collation              |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| jan_int           | InnoDB |      10 | Dynamic    | 9739094 |             43 |   422510592 |               0 |            0 |   4194304 |           NULL | utf8mb4_unicode_520_ci |  
| jan_int_index     | InnoDB |      10 | Dynamic    | 9740329 |             43 |   420413440 |               0 |    132857856 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_char          | InnoDB |      10 | Dynamic    | 9726613 |             51 |   500170752 |               0 |            0 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_char_index    | InnoDB |      10 | Dynamic    | 9719059 |             52 |   513802240 |               0 |    202342400 |   5242880 |           NULL | utf8mb4_unicode_520_ci |  
| jan_varchar       | InnoDB |      10 | Dynamic    | 9722049 |             53 |   521142272 |               0 |            0 |   7340032 |           NULL | utf8mb4_unicode_520_ci |   
| jan_varchar_index | InnoDB |      10 | Dynamic    | 9738381 |             49 |   486539264 |               0 |    202375168 |   7340032 |           NULL | utf8mb4_unicode_520_ci | 
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

Ma conclusion est qu'il n'y a pas de différence de performances pour ce cas d'utilisation particulier.

Jan Żankowski
la source
Je sais qu'il est tard maintenant, mais j'aurais été curieux de voir les résultats si vous aviez choisi une chaîne moins idéale pour la condition where. "califo [rnia]" était idéal car il pouvait éliminer les incompatibilités après avoir comparé le premier caractère, n'ayant besoin que de vérifier davantage les correspondances réelles; quelque chose comme "newham" aurait donné des résultats plus intéressants car il serait nouveau de comparer plus de caractères pour éliminer toutes les discordances. De plus, en limitant vos nombres entiers de cette façon, vous accumulez également les chances contre eux, je leur aurais donné au moins 26 valeurs.
Uueerdo
15
Étonnant que dans une question vieille de 10 ans, ce ne soit que l'une des deux réponses qui ne sont pas seulement des spéculations et qui reposent sur des repères réels.
Adrian Baker
1
Mais vos tables n'ont pas de clé primaire, qui en fait dans InnoDB est une structure de données triées. La vitesse entre le tri des entiers et le tri des chaînes doit être différente.
Melkor
1
@Melkor Fair point que j'utilise à la INDEXplace PRIMARY KEY. Je ne me souviens pas de mon raisonnement - j'ai probablement supposé qu'il s'agissait PRIMARY KEYsimplement d'une INDEXcontrainte 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.
Jan Żankowski
1
L'opération de recherche nécessite également des comparaisons sur le champ de clé primaire (comme une recherche binaire), où int devrait être un peu plus rapide que varchar. Mais comme vos expériences l'ont suggéré, ce n'est pas si évident (ou peut-être parce que vous n'aviez pas de clé primaire, donc les requêtes étaient toutes plus lentes). Je pense que c'est la même chose pour l'insertion et la recherche.
Melkor
38

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. ..

Charles Bretana
la source
Sûr? La plupart des formats de données ne sont-ils pas basés sur des lignes? Il y a d'autres données en dehors des clés. Le facteur 5 n'est-il pas utopique?
ManuelSchneid3r
1
@ manuelSchneid3r, quoi? utopique? Non, le facteur 5 n'est pas "utopique". Il est juste 20 divisé par 4. Et que signifie «basé sur le format des données»? Les indices ne sont pas "basés sur des lignes", ce sont des arborescences équilibrées.
Charles Bretana
36

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.

Timothy Khouri
la source
42
sans signification sans savoir combien de temps duraient les varchars ... S'ils étaient de 100 octets widem, alors garanti que vous n'obtiendrez pas les mêmes performances qu'un entier de 4 octets
Charles Bretana
6
Il serait également utile de savoir quelle base de données vous utilisez et quelle version de la base de données. Le réglage des performances est presque toujours travaillé et amélioré d'une version à l'autre.
Dave Black
VARCHAR est vraiment important pour la taille de l'index. Et l'index détermine la quantité pouvant être stockée en mémoire. Et les index en mémoire sont bien plus rapides que ceux qui ne le sont pas. Il se peut que pour vos 10 millions de lignes, vous ayez 250 Mo de mémoire disponible pour cet index, et tout allait bien. Mais si vous avez 100m de lignes, vous serez moins bien dans cette mémoire.
Paul Draper
9

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.

Joël Coehoorn
la source
2
Savez-vous avec certitude que cela coûterait cher? Ou êtes-vous juste en train de deviner?
Steve McLeod
Bien sûr, cela dépend de l'implémentation de rdbms, mais d'après ce que je comprends, la plupart des serveurs conserveront le hachage de la valeur réelle à des fins d'indexation. Même ainsi, et même s'il s'agit d'un hachage relativement court (par exemple, 10 octets), il est encore plus difficile de comparer 2 hachages de 10 octets que 2 entiers de 4 octets.
Joel Coehoorn
N'utilisez JAMAIS une clé longue (large) pour les jointures ... Mais si c'est la meilleure représentation de ce qui est unique pour les lignes de la table, alors il vaut mieux avoir une clé unique (ou un index - ce qui est la même chose) sur le table en utilisant ces valeurs naturelles. Les clés ne sont pas là pour les jointures, vous pouvez vous joindre à tout ce que votre cœur désire. Les clés sont là pour assurer la cohérence des données.
Charles Bretana
6

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:

ex.
id value
1 A
2 B
3 C

Update 3 to D
id value
1 A
2 B
3 D

Update 2 to C
id value
1 A
2 C
3 D

Update 3 to B
id value
1 A
2 C
3 B

Tout dépend de ce dont vous devez vraiment vous soucier dans votre structure et de ce qui signifie le plus.

LeppyR64
la source
3

Cas courants où un substitut AUTO_INCREMENTfait mal:

Un modèle de schéma commun est un mappage plusieurs-à-plusieurs :

CREATE TABLE map (
    id ... AUTO_INCREMENT,
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(id),
    UNIQUE(foo_id, bar_id),
    INDEX(bar_id) );

Les performances de ce modèle sont bien meilleures, en particulier lors de l'utilisation d'InnoDB:

CREATE TABLE map (
    # No surrogate
    foo_id ...,
    bar_id ...,
    PRIMARY KEY(foo_id, bar_id),
    INDEX      (bar_id, foo_id) );

Pourquoi?

  • Les clés secondaires InnoDB nécessitent une recherche supplémentaire; en déplaçant la paire dans le PK, cela est évité pour une direction.
  • L'index secondaire est "couvrant", il n'a donc pas besoin de recherche supplémentaire.
  • Cette table est plus petite en raison de la suppression d' idun index.

Un autre cas ( pays ):

country_id INT ...
-- versus
country_code CHAR(2) CHARACTER SET ascii

Trop souvent, le novice normalise country_code en 4 octets INTau lieu d'utiliser une chaîne «naturelle» de 2 octets, presque inchangée. Plus rapide, plus petit, moins de JOIN, plus lisible.

Rick James
la source
2

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.

Herman J. Radtke III
la source
2

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:

+----------+          +---------+
| Accident |>--------<| Vehicle |
+-----v----+ 1      * +----v----+
     1|                    |1
      |    +----------+    |
      +---<| Casualty |>---+
         * +----------+ *

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.

Diego Duarte
la source
1
On dirait que vous devez vous pencher sur le partitionnement.
jcoffland
2

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.

Volksman
la source
0

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.

Dexygène
la source
0

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.

Vinod
la source
0

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)

Shadi Namrouti
la source