Clé primaire ou index unique?

127

Au travail, nous avons une grande base de données avec des index uniques au lieu de clés primaires et tout fonctionne bien.

Je conçois une nouvelle base de données pour un nouveau projet et j'ai un dilemme:

Dans la théorie DB, la clé primaire est un élément fondamental, c'est OK, mais dans les projets REAL, quels sont les avantages et les inconvénients des deux?

Qu'utilisez-vous dans les projets?

EDIT: ... et qu'en est-il des clés primaires et de la réplication sur le serveur MS SQL?

Cicik
la source
2
Il y a quelques considérations supplémentaires discutées ici (bien qu'avec le contexte supplémentaire d'un index de couverture) - dba.stackexchange.com/questions/21554/…
StuartLC
REMARQUE: SQLite est différent en ce qu'il autorise la clé primaire à être nulle, par rapport à la norme courante en raison d'un problème hérité. sqlite.org/lang_createtable.html
bitinn

Réponses:

168

Qu'est-ce qu'un index unique?

Un index unique sur une colonne est un index sur cette colonne qui applique également la contrainte selon laquelle vous ne pouvez pas avoir deux valeurs égales dans cette colonne sur deux lignes différentes. Exemple:

CREATE TABLE table1 (foo int, bar int);
CREATE UNIQUE INDEX ux_table1_foo ON table1 (toto); - Créez un index unique sur foo.

INSERT INTO table1 (foo, bar) VALUES (1, 2); -- D'ACCORD
INSERT INTO table1 (foo, bar) VALUES (2, 2); -- D'ACCORD
INSERT INTO table1 (foo, bar) VALUES (3, 1); -- D'ACCORD
INSERT INTO table1 (foo, bar) VALUES (1, 4); -- Échoue!

Entrée en double '1' pour la clé 'ux_table1_foo'

La dernière insertion échoue car elle enfreint l'index unique sur la colonne foolorsqu'il essaie d'insérer la valeur 1 dans cette colonne une deuxième fois.

Dans MySQL, une contrainte unique autorise plusieurs NULL.

Il est possible de créer un index unique sur plusieurs colonnes.

Clé primaire contre index unique

Les choses qui sont les mêmes:

  • Une clé primaire implique un index unique.

Des choses différentes:

  • Une clé primaire implique également NOT NULL, mais un index unique peut être nullable.
  • Il ne peut y avoir qu'une seule clé primaire, mais il peut y avoir plusieurs index uniques.
  • S'il n'y a pas d'index cluster défini, la clé primaire sera l'index cluster.
Mark Byers
la source
4
Notez qu'un index unique est un index sur une colonne n'est pas entièrement précis car un index unique ou une clé primaire peut inclure plusieurs colonnes.
Alex Jasmin
2
@Alexandre Jasmin: merci fixe. La partie sur plusieurs colonnes est mentionnée plus loin.
Mark Byers
En ce qui concerne les valeurs nulles, les normes ansi autorisent plusieurs valeurs nulles dans un ensemble de données avec une contrainte unique, et c'est également l'implémentation sur Oracle et PostgreSQL. Je crois que SQL Server n'autorise qu'une seule valeur nulle.
David Aldridge
3
mais je ne l'ai toujours pas compris, comme quand utiliser la clé primaire ou quand utiliser un index unique? ou peut être les deux dans les mêmes situations.
Amit le
33

Vous pouvez le voir comme ceci:

Une clé primaire est unique

Une valeur unique ne doit pas nécessairement être la représentaion de l'élément

Sens?; Eh bien, une clé primaire est utilisée pour identifier l'élément, si vous avez une «personne», vous aimeriez avoir un numéro d'identification personnel (SSN ou autre) qui est principal pour votre personne.

D'un autre côté, la personne peut avoir un e-mail qui est unique, mais qui ne l'identifie pas.

J'ai toujours des clés primaires, même dans les tables de relations (la table du milieu / table de connexion), je pourrais les avoir. Pourquoi? Eh bien, j'aime suivre une norme lors du codage, si la "Personne" a un identifiant, la Voiture a un identifiant, eh bien, alors la Personne -> Voiture devrait avoir un identifiant aussi!

Filip Ekberg
la source
Dans vos tables de relations: voulez-vous dire que vous introduisez une nouvelle colonne avec une clé primaire artificielle (un entier par exemple) ou utilisez-vous une clé primaire composée (person_id, car_id)?
3
la clé primaire (person_id, car_id) serait la meilleure. Mais je crée généralement une nouvelle colonne, bien sûr que cela donne des frais généraux, mais je pense que c'est bien. Vous ne savez jamais si vous souhaitez vous rapporter à une relation spécifique dans un scénario ultérieur.
Filip Ekberg
1
L'autre chose que fait la clé primaire de substitution pour votre table composite / jointure est de faciliter la maintenance des tâches manuelles.
Robert C. Barth
2
Vous n'avez besoin que d'une clé primaire si vous allez avoir des enfants. Pourquoi ajouter une colonne et une séquence si la valeur n'apparaît nulle part, si la valeur ne sert à rien? C'est un travail pour empêcher Access de demander un PK. Faites une PK si vous avez besoin d'identifier le dossier chez un enfant, sinon c'est un gaspillage.
3
Si cela n'a rien à voir avec les relations, avec quoi cela a-t-il à voir? Vous pointez vers un champ et dites, c'est primaire. Et? Alors que se passe-t-il? Et s'il n'y a pas de pk naturel, j'ajoute une colonne et une séquence et un déclencheur et tout parce que ____? Certains ont juste besoin d'être primaires. J'évite les règles sans raison.
10

Les clés étrangères fonctionnent avec des contraintes uniques ainsi que des clés primaires. À partir de Books Online:

Une contrainte FOREIGN KEY ne doit pas être liée uniquement à une contrainte PRIMARY KEY dans une autre table; il peut également être défini pour référencer les colonnes d'une contrainte UNIQUE dans une autre table

Pour la réplication transactionnelle, vous avez besoin de la clé primaire. À partir de Books Online:

Les tables publiées pour la réplication transactionnelle doivent avoir une clé primaire. Si une table se trouve dans une publication de réplication transactionnelle, vous ne pouvez désactiver aucun index associé à des colonnes de clé primaire. Ces index sont requis par la réplication. Pour désactiver un index, vous devez d'abord supprimer la table de la publication.

Les deux réponses concernent SQL Server 2005.

Jonas Lincoln
la source
CELA me fait peur (première citation). Pourquoi? J'ai une table de personne avec un identifiant arbitraire qui est mon PK mais je décide d'ajouter un Royaume-Uni au téléphone, à l'e-mail et au SSN ... alors maintenant 4 tables différentes se joignent à une personne sur 4 colonnes différentes? Je pense que je renoncerais à toute flexibilité que vous pourriez obtenir pour la cohérence.
5

Le choix du moment d'utilisation d'une clé primaire de substitution par opposition à une clé naturelle est délicat. Des réponses telles que, toujours ou jamais, sont rarement utiles. Je trouve que cela dépend de la situation.

A titre d'exemple, j'ai les tableaux suivants:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

Nous avons deux tables d'entité ( toll_boothset cars) et une table de transaction ( drive_through). La toll_boothtable utilise une clé de substitution car elle n'a aucun attribut naturel dont la modification n'est pas garantie (le nom peut facilement être changé). La carstable utilise une clé primaire naturelle car elle possède un identifiant unique non modifiable ( vin). ledrive_through table de transaction utilise une clé de substitution pour une identification facile, mais a également une contrainte unique sur les attributs qui sont garantis uniques au moment où l'enregistrement est inséré.

http://database-programmer.blogspot.com a quelques bons articles sur ce sujet particulier.

aekeus
la source
4

Il n'y a pas d'inconvénients des clés primaires.

Pour ajouter juste quelques informations aux réponses @MrWiggles et @Peter Parker, lorsque la table n'a pas de clé primaire, par exemple, vous ne pourrez pas modifier les données dans certaines applications (elles finiront par dire qc comme ne peut pas modifier / supprimer des données sans clé primaire). Postgresql permet à plusieurs valeurs NULL d'être dans la colonne UNIQUE, PRIMARY KEY n'autorise pas les NULL. Certains ORM qui génèrent du code peuvent également rencontrer des problèmes avec les tables sans clés primaires.

METTRE À JOUR:

Autant que je sache, il n'est pas possible de répliquer des tables sans clés primaires dans MSSQL, du moins sans problèmes ( détails ).

empi
la source
Il y a une surcharge lorsque de nouvelles lignes sont insérées ou que cette colonne est mise à jour.
3

Si quelque chose est une clé primaire, selon votre moteur de base de données, la table entière est triée par clé primaire. Cela signifie que les recherches sont beaucoup plus rapides sur la clé primaire car elle n'a pas à faire de déréférencement comme cela a à voir avec tout autre type d'index. En plus de cela, ce n'est que de la théorie.

Ray Hidayat
la source
3
la table sera triée par l'index clusterisé pas nécessairement par la clé primaire.
Ray Booysen
1
il se trouve que la plupart des gens définissent leur clé primaire comme l'index cluster.
Ray Booysen
Ce que nous savons est souvent une très mauvaise idée, à moins que nous n'aimions les points chauds et les arbres d'index déséquilibrés dans nos tables, bien sûr ...
Mike Woodhouse
1
Ce n'est pas TOUJOURS une très mauvaise idée. Connaissez vos données, connaissez votre SGBDR, sachez ce que signifient les choix. Rarement le choix est TOUJOURS bon ou mauvais. S'il y en avait TOUJOURS un, la base de données le rendrait obligatoire ou le refuserait. Ils vous donnent le choix parce que «ça dépend».
2

En plus de ce que les autres réponses ont dit, certaines bases de données et certains systèmes peuvent nécessiter la présence d' un primaire. Une situation me vient à l'esprit; lors de l'utilisation de la réplication d'entreprise avec Informix, un PK doit être présent pour qu'une table participe à la réplication.

tddmonkey
la source
2

Tant que vous n'autorisez pas NULL pour une valeur, elles doivent être gérées de la même manière, mais la valeur NULL est gérée différemment sur les bases de données (AFAIK MS-SQL n'autorise pas plus d'une (1) valeur NULL, mySQL et Oracle le permettent , si une colonne est UNIQUE) Vous devez donc définir cette colonne NOT NULL UNIQUE INDEX

Peter Parker
la source
1
MS-SQL autorise plusieurs valeurs NULL dans une colonne qui a un index unique, comme le devrait chaque SGBDR. Pensez-y de cette façon: NULL n'est pas une valeur, donc lorsque vous insérez un deuxième NULL, il ne correspondra jamais à une valeur existante. L'expression (NULL == NULL) n'évalue pas à vrai ou faux, elle s'évalue à NULL.
gregmac
merci gregmac, je n'étais pas sûr, si MS suit cela. Je me suis souvenu de quelques bizarreries MS avec ceci, cependant il y a quelques années (avant 2000) et pourrait aussi être une vieille toux d'
Peter Parker
2

Il n'y a pas de clé primaire dans la théorie des données relationnelles, il faut donc répondre à votre question sur le plan pratique.

Les index uniques ne font pas partie de la norme SQL. L'implémentation particulière d'un SGBD déterminera quelles sont les conséquences de la déclaration d'un index unique.

Dans Oracle, la déclaration d'une clé primaire entraînera la création d'un index unique en votre nom, la question est donc presque sans objet. Je ne peux pas vous parler des autres produits SGBD.

Je suis favorable à la déclaration d'une clé primaire. Cela a pour effet d'interdire les valeurs NULL dans la (les) colonne (s) clé ainsi que d'interdire les doublons. Je suis également favorable à la déclaration de contraintes REFERENCES pour appliquer l'intégrité de l'entité. Dans de nombreux cas, déclarer un index sur le (s) coulmn (s) d'une clé étrangère accélérera les jointures. Ce type d'index ne doit en général pas être unique.

Walter Mitty
la source
Une clé primaire dans MS SQL Server est toujours à la fois UNIQUE et NOT NULL - par exemple, c'est vraiment juste un index Unique, mais avec la restriction supplémentaire qu'elle ne peut pas être NULL.
marc_s
Oracle peut appliquer une contrainte unique avec un index non unique. Je serais surpris si le MSSS ne pouvait pas. Dire "ce n'est vraiment qu'un index unique" est un mauvais service.
"Dans de nombreux cas, déclarer un index sur le (s) coulmn (s) d'une clé étrangère accélérera les jointures." ce n'est presque toujours pas vrai dans un monde d'entreposage de données où les jointures par hachage seraient préférables si elles sont disponibles.
JAC2703
Le PO n'a pas mentionné les entrepôts. Je ne sais pas comment les loins de hachage fonctionnent sur le serveur SQL. Quelle quantité de travail peut être effectuée au moment de la mise à jour de l'entrepôt.
Walter Mitty
2

Les INDEXES CLUSTERES présentent certains inconvénients par rapport aux INDICES UNIQUES.

Comme déjà indiqué, un INDEX CLUSTERED classe physiquement les données dans la table.

Cela signifie que lorsque vous en avez beaucoup en cas d'insertion ou de suppression sur une table contenant un index clusterisé, à chaque fois (enfin, presque, en fonction de votre facteur de remplissage) vous modifiez les données, la table physique doit être mise à jour pour rester triée.

Dans des tables relativement petites, cela convient, mais lorsque vous accédez à des tables contenant des données en Go et que les insertions / suppressions affectent le tri, vous rencontrerez des problèmes.

Nico Bester
la source
Quel est donc l'avantage? les requêtes triées sont-elles plus rapides? est-ce mieux pour un cas d'utilisation lorsque vous écrivez la plupart de vos données une fois (ou rarement) et que vous les interrogez tout le temps?
Buffalo
1

Je ne crée presque jamais de table sans clé primaire numérique. S'il y a aussi une clé naturelle qui doit être unique, je mets également un index unique dessus. Les jointures sont plus rapides sur les entiers que sur les clés naturelles multicolonnes, les données ne doivent changer qu'à un seul endroit (les clés naturelles ont tendance à avoir besoin d'être mises à jour, ce qui est une mauvaise chose lorsqu'elles sont dans les relations clé primaire - clé étrangère). Si vous avez besoin d'une réplication, utilisez un GUID au lieu d'un entier, mais pour la plupart, je préfère une clé lisible par l'utilisateur, surtout s'il a besoin de la voir pour faire la distinction entre John Smith et John Smith.

Les rares fois où je ne crée pas de clé de substitution, c'est lorsque j'ai une table de jointure qui est impliquée dans une relation plusieurs-à-plusieurs. Dans ce cas, je déclare les deux champs comme clé primaire.

HLGEM
la source
«Je ne crée presque jamais de table sans clé primaire numérique»: pourquoi toujours numérique? Une clé primaire n'a pas besoin d'être numérique (elle ne doit pas non plus être AUTO_INCREMENT d'ailleurs).
Hibou57
@ Hinou57, parce que j'ai trouvé que les clés naturelles sont rarement uniques et qu'elles sont presque toujours modifiables. Les jointures Furthere sur les intergers sont généralement beaucoup plus rapides que les jointures sur les clés naturelles varcahrr ou des clés composites pires. Je ne les utiliserais pas la plupart du temps. Cela peut varier en fonction du type d'informations que vous stockez dans votre base de données, mais d'après mon expérience personnelle, j'ai trouvé les clés naturelles extrêmement peu fiables au fil du temps.
HLGEM
Merci pour la réponse HLGEM. Que voulez-vous dire par non fiable? Performance? (J'espère que ce n'est pas une question de fiabilité au sens de l'intégrité des données). Je suis un peu surpris par vos mots, car je pensais qu'utiliser des clés entières ou des clés plus naturelles comme VARCHAR court ne ferait probablement qu'une petite différence car le hachage est utilisé partout, même avec les moteurs DB les plus simples.
Hibou57
Ils ne sont pas fiables dans de nombreux cas car ils ne sont pas uniques de manière fiable même s'ils sont censés l'être. Ils ne sont pas fiables car ils changent et cela peut affecter des millions d'enregistrements dans une mise à jour. C'est mon expérience d'avoir vu et géré ou interrogé des données ou importées des données de centaines de bases de données qui stockent des données sur de nombreux types d'informations différents.
HLGEM
1

Je crois comprendre qu'une clé primaire et un index unique avec une contrainte non nulle sont identiques (*); et je suppose que l'un choisit l'un ou l'autre en fonction de ce que la spécification indique ou implique explicitement (une question de ce que vous voulez exprimer et appliquer explicitement). S'il nécessite un caractère unique et non nul, alors faites-en une clé primaire. S'il arrive que toutes les parties d'un index unique ne soient pas nulles sans aucune exigence, alors faites-en simplement un index unique.

La seule différence restante est que vous pouvez avoir plusieurs index uniques non nuls, alors que vous ne pouvez pas avoir plusieurs clés primaires.

(*) Sauf une différence pratique: une clé primaire peut être la clé unique par défaut pour certaines opérations, comme la définition d'une clé étrangère. Ex. si l'on définit une clé étrangère référençant une table et ne fournit pas le nom de la colonne, si la table référencée a une clé primaire, alors la clé primaire sera la colonne référencée. Sinon, la colonne référencée devra être nommée explicitement.

D'autres ici ont mentionné la réplication de base de données, mais je n'en sais rien.

Hibou57
la source
0

L'index unique peut avoir une valeur NULL. Il crée un INDEX NON CLUSTERED. La clé primaire ne peut pas contenir de valeur NULL. Il crée un INDEX CLUSTERED.

Chirag
la source
0

Dans MSSQL, les clés primaires doivent augmenter de manière monotone pour de meilleures performances sur l'index clusterisé. Par conséquent, un entier avec insertion d'identité est meilleur que toute clé naturelle qui pourrait ne pas augmenter de manière monotone.

Markus
la source
-1

Si ça m 'allait...

Vous devez satisfaire les exigences de la base de données et de vos applications.

L'ajout d'un entier à incrémentation automatique ou d'une colonne d'identifiant long à chaque table pour servir de clé primaire prend en charge les exigences de la base de données.

Vous ajouteriez ensuite au moins un autre index unique à la table à utiliser par votre application. Ce serait l'index sur employee_id, ou account_id, ou customer_id, etc. Si possible, cet index ne doit pas être un index composite.

Je préférerais les indices sur plusieurs domaines individuellement aux indices composites. La base de données utilisera les index de champ unique chaque fois que la clause where inclut ces champs, mais elle n'utilisera un composite que lorsque vous fournissez les champs exactement dans le bon ordre - ce qui signifie qu'elle ne peut pas utiliser le deuxième champ dans un index composite à moins que vous ne fournissiez le premier et le second de votre clause where.

Je suis tout à fait favorable à l'utilisation d'indices de type calculé ou de fonction - et je recommanderais de les utiliser sur des indices composites. Il est très facile d'utiliser l'index de fonction en utilisant la même fonction dans votre clause where.

Cela prend en charge les exigences de votre application.

Il est fort probable que d'autres index non primaires soient en fait des mappages de cette valeur de clé d'index vers une valeur de clé primaire, pas celle de rowid (). Cela permet des opérations de tri physiques et des suppressions sans avoir à recréer ces index.

Rodney P. Barbati
la source