Dans mes bases de données, j'ai tendance à prendre l'habitude d'avoir une clé primaire entière à incrémentation automatique avec le nom id
pour chaque table que je crée afin d'avoir une recherche unique pour une ligne particulière.
Est-ce considéré comme une mauvaise idée? Y a-t-il des inconvénients à le faire de cette façon? Parfois, j'ai plusieurs indices comme id, profile_id, subscriptions
où id
est l'identifiant unique, profile_id
des liens vers le id
étranger d'une table Profile
, etc.
Ou existe-t-il des scénarios dans lesquels vous ne souhaitez pas ajouter un tel champ?
Ce n'est jamais une mauvaise idée d'avoir un identifiant de ligne unique garanti. Je suppose que je ne devrais pas dire jamais - mais allons-y avec l'écrasante majorité du temps, c'est une bonne idée.
Les inconvénients potentiels théoriques incluent un index supplémentaire à maintenir et un espace de stockage supplémentaire utilisé. Cela n'a jamais été une raison suffisante pour que je n'en utilise pas.
Je suis en désaccord avec toutes les réponses précédentes. Il y a de nombreuses raisons pour lesquelles c'est une mauvaise idée d'ajouter un champ d'incrémentation automatique dans toutes les tables.
Si vous avez une table où il n'y a pas de clés évidentes, un champ d'incrémentation automatique semble être une bonne idée. Après tout, vous ne voulez pas select * from blog where body = '[10000 character string]'
. Vous préférez select * from blog where id = 42
. Je dirais que dans la plupart de ces cas, ce que vous voulez vraiment, c'est un identifiant unique; pas un identifiant unique séquentiel. Vous voudrez probablement utiliser un identifiant universellement unique à la place.
Il existe des fonctions dans la plupart des bases de données pour générer des identifiants uniques aléatoires (uuid
dans mysql, postgres. newid
dans mssql). Ceux-ci vous permettent de générer des données dans plusieurs bases de données, sur différentes machines, à tout moment, sans connexion réseau entre elles, tout en fusionnant les données sans aucun conflit. Cela vous permet de configurer plus facilement plusieurs serveurs et même des centres de données, comme par exemple, avec des microservices.
Cela évite également aux attaquants de deviner les URL des pages auxquelles ils ne devraient pas avoir accès. S'il y a un https://example.com/user/1263
il y a probablement un https://example.com/user/1262
ainsi que. Cela pourrait permettre l'automatisation d'un exploit de sécurité dans la page de profil utilisateur.
Il y a aussi beaucoup de cas où une colonne uuide est inutile ou même nuisible. Disons que vous avez un réseau social. Il existe une table users
et une table friends
. La table d'amis contient deux colonnes d'ID utilisateur et un champ d'incrémentation automatique. Tu veux 3
pour être ami avec 5
, donc vous insérez 3,5
dans la base de données. La base de données ajoute un identifiant d'incrémentation automatique et stocke 1,3,5
. D'une manière ou d'une autre, l'utilisateur 3
clique à nouveau sur le bouton "Ajouter un ami". Vous insérez 3,5
dans la base de données, la base de données ajoute un identifiant d'incrémentation automatique et insère 2,3,5
. Mais maintenant 3
et 5
sont amis deux fois! C'est une perte d'espace, et si vous y réfléchissez, la colonne d'auto-incrémentation l'est aussi. Tout ce dont vous avez besoin pour voir si a
et b
sont amis est de sélectionner la ligne avec ces deux valeurs. Ils sont, ensemble, un identifiant de ligne unique. (Vous voudrez probablement écrire de la logique pour vous assurer que 3,5
et 5,3
sont dédupliqués.)
Il y a encore des cas où les identifiants séquentiels peuvent être utiles, comme lors de la construction d'un raccourcisseur d'URL, mais surtout (et même avec le raccourcisseur d'URL) un identifiant unique généré de manière aléatoire est ce que vous voulez vraiment utiliser à la place.
TL; DR: tilisez les UUID au lieu de l'incrémentation automatique, si vous ne disposez pas déjà d'un moyen unique d'identifier chaque ligne.
Les clés auto-cimentaires ont surtout des avantages.
Mais certains inconvénients possibles pourraient être:
Voici une section d'article Wikipedia sur les inconvénients des clés de substitution.
Juste pour être contraire, non, vous n'avez PAS besoin d'avoir toujours un PK AutoInc numérique.
Si vous analysez soigneusement vos données, vous identifiez souvent des clés naturelles dans les données. C'est souvent le cas lorsque les données ont une signification intrinsèque pour l'entreprise. Parfois, les PK sont des artefacts d'anciens systèmes que les utilisateurs professionnels utilisent comme deuxième langue pour décrire les attributs de leur système. J'ai vu des numéros de VIN de véhicule utilisés comme clé primaire d'une table "Véhicule" dans un système de gestion de flotte par exemple.
Quelle qu'en soit l'origine, SI vous avez déjà un identifiant unique, utilisez-le. Ne créez pas une deuxième clé primaire vide de sens; c'est du gaspillage et peut provoquer des erreurs.
Parfois, vous pouvez utiliser un PK AutoInc pour générer une valeur significative pour le client, par exemple Numéros de politique. Définir la valeur de départ sur quelque chose de sensé et appliquer des règles commerciales sur les zéros en tête, etc.
Lorsque vous avez un petit nombre de valeurs relativement statiques, utilisez des valeurs qui ont du sens pour l'utilisateur du système. Pourquoi utiliser 1,2,3 alors que vous pouvez utiliser L, C, H où L, H et C représentent la vie, la voiture et l'habitation dans un contexte de "type de police" d'assurance, ou, pour revenir à l'exemple VIN, que diriez-vous d'utiliser "TO "pour Toyota? Toutes les voitures Toyata ont un VIN qui commence par "TO". C'est une chose de moins à retenir pour les utilisateurs, ce qui les rend moins susceptibles d'introduire des erreurs de programmation et d'utilisateur et peut même être un substitut utilisable pour une description complète dans les rapports de gestion, ce qui simplifie les rapports. à écrire et peut-être plus rapide à générer.
Un développement ultérieur de ceci est probablement "un pont trop loin" et je ne le recommande généralement pas, mais je l'inclus pour être complet et vous pouvez en trouver une bonne utilisation. Autrement dit, utilisez la description comme clé primaire. Pour des données qui changent rapidement, c'est une abomination. Pour très données statiques signalées le All The Time, peut-être pas. Il suffit de le mentionner pour qu'il soit là comme une possibilité.
J'utilise des PK AutoInc, j'engage simplement mon cerveau et cherche d'abord de meilleures alternatives. L'art de la conception de bases de données rend quelque chose de significatif qui peut être interrogé rapidement. Avoir trop de jointures empêche cela.
EDIT Un autre cas crucial où vous n'avez pas besoin d'un PK autogénéré est le cas des tables qui représentent l'intersection de deux autres tables. Pour rester dans l'analogie avec la voiture, une voiture a 0..n accessoires, chaque accessoire peut être trouvé sur de nombreuses voitures. Donc, pour représenter cela, vous créez une table Car_Accessory contenant les PK de Car and Accessory et d'autres informations pertinentes sur le lien Dates, etc.
Ce dont vous n'avez pas (généralement) besoin est un PK AutoInc sur cette table - il ne sera accessible que via la voiture "dites-moi quels accessoires sont sur cette voiture" ou depuis l'accessoire "dites-leur quelles voitures ont cet accessoire"
De nombreuses tables ont déjà un identifiant unique naturel. N'ajoutez pas une autre colonne d'ID unique (incrémentation automatique ou autre) à ces tables. Utilisez plutôt l'identifiant unique naturel. Si vous ajoutez un autre identifiant unique, vous avez essentiellement une redondance (duplication ou dépendance) dans vos données. Cela va à l'encontre des principes de normalisation. Un identifiant unique dépend de l'autre pour la précision. Cela signifie qu'ils doivent être parfaitement synchronisés à en tout temps dans chaque système qui gère ces lignes. C'est juste une autre fragilité de l'intégrité de vos données que vous ne voulez pas vraiment devoir gérer et valider à long terme.
De nos jours, la plupart des tables n'ont pas vraiment besoin de l'amélioration très mineure des performances qu'une colonne d'ID unique supplémentaire donnerait (et parfois, cela nuit même aux performances). En règle générale en informatique, évitez les redondances comme le peste! Résistez-le partout où il vous est suggéré. C'est de l'anathème. Et tenez compte de la citation. Tout devrait être aussi simple que possible, mais pas plus simple. N'ayez pas deux identifiants uniques où un suffira, même si le naturel semble moins rangé.
Chaque règle a une exception, vous n'aurez donc peut-être pas besoin d'un ID d'auto-incrémentation entier sur les tables intermédiaires utilisées pour l'exportation/l'importation et sur les tables unidirectionnelles similaires ou les tables temporaires. Vous préféreriez également les GUID au lieu des ID sur les systèmes distribués.
De nombreuses réponses suggèrent que la clé unique existante devrait être prise. Eh bien, même s'il contient 150 caractères? Je ne pense pas.
Maintenant mon point principal:
Il semble que les opposants à l'ID à incrémentation automatique parlent de petites bases de données contenant jusqu'à 20 tables. Là, ils peuvent se permettre une approche individuelle de chaque table.
MAIS une fois que vous avez un ERP avec plus de 400 tables, ayant un ID d'auto-incrémentation n'importe où) (sauf les cas mentionnés ci-dessus) c'est tout à fait logique. Vous ne comptez pas sur d'autres domaines uniques, même s'ils sont présents et sécurisés pour l'unicité.
JOIN
tables, sans avoir besoin de vérifier quelles sont les clés.Sur les grands systèmes, il peut être utile d'ignorer les avantages mineurs de ces clés primaires individuelles et d'utiliser systématiquement l'ID d'auto-incrémentation entière dans la plupart des cas. L'utilisation de champs uniques existants comme clés primaires permet peut-être d'économiser quelques octets par enregistrement, mais le stockage supplémentaire ou le temps d'indexation ne posent aucun problème dans les moteurs de base de données d'aujourd'hui. En fait, vous perdez beaucoup plus d'argent et de ressources sur le temps perdu des développeurs/mainteneurs. Le logiciel d'aujourd'hui devrait être optimisé pour le temps et les efforts des programmeurs - quelle approche avec des identifiants cohérents remplit mieux.
Les conceptions superflues ne sont pas une bonne pratique. C'est à dire. - il n'est pas recommandé d'avoir toujours une clé primaire à incrémentation automatique lorsque celle-ci n'est pas nécessaire.
Voyons un exemple où l'on n'est pas nécessaire.
Vous avez une table pour les articles - elle a une clé primaire int id
et une colonne varchar nommée title
.
Vous disposez également d'une table remplie de catégories d'articles –id
clé primaire int, varchar name
.
Une ligne du tableau Articles a un id
sur 5 et un title
"Comment faire cuire l'oie avec du beurre". Vous souhaitez lier cet article aux lignes suivantes de votre tableau Catégories: "Fowl" (id: 20), "Goose" (id: 12), "Cooking" (id: 2), "Beurre" (id: 9).
Maintenant, vous avez 2 tableaux: articles et catégories. Comment créez-vous la relation entre les deux?
Vous pourriez avoir une table avec 3 colonnes: id (clé primaire), article_id (clé étrangère), category_id (clé étrangère). Mais maintenant, vous avez quelque chose comme:
| id | a_id | c_id | | 1 | 5 | 20 | | 2 | 5 | 12 | | 3 | 5 | 2 |
Une meilleure solution consiste à avoir une clé primaire composée de 2 colonnes.
| a_id | c_id | | 5 | 20 | | 5 | 12 | | 5 | 2 |
Cela peut être accompli en faisant:
create table articles_categories (
article_id bigint,
category_id bigint,
primary key (article_id, category_id)
) engine=InnoDB;
Une autre raison de ne pas utiliser un entier à incrémentation automatique est si vous utilisez des UUID pour votre clé primaire.
Les UUID sont par définition uniques, ce qui accomplit la même chose que l'utilisation d'entiers uniques. Ils ont également leurs propres avantages (et inconvénients) par rapport aux entiers. Par exemple, avec un UUID, vous savez que la chaîne unique à laquelle vous faites référence pointe vers un enregistrement de données particulier; cela est utile dans les cas où vous n'avez pas 1 base de données centrale ou lorsque les applications ont la possibilité de créer des enregistrements de données hors ligne (puis de les télécharger dans la base de données à une date ultérieure).
En fin de compte, vous ne devez pas considérer les clés primaires comme une chose. Vous devez les considérer comme la fonction qu'ils remplissent. Pourquoi avez-vous besoin de clés primaires? Pour pouvoir identifier de manière unique des ensembles spécifiques de données à partir d'une table à l'aide d'un champ qui ne sera pas modifié à l'avenir. Avez-vous besoin d'une colonne particulière appelée id
pour ce faire, ou pouvez-vous baser cette identification unique sur d'autres données (immuables)?
Une clé primaire auto-incrémentée (identité) est une bonne idée, sauf pour noter qu'elle n'a pas de sens en dehors du contexte de la base de données et des clients immédiats de cette base de données. Par exemple, si vous transférez et stockez certaines des données dans une autre base de données, puis procédez à l'écriture de données différentes dans les deux tables de base de données, les identifiants divergent - c'est-à-dire que les données avec un identifiant de 42 dans une base de données ne correspondent pas nécessairement aux données avec un identifiant de 42 dans l'autre.
Compte tenu de cela, s'il est nécessaire de pouvoir toujours identifier des lignes uniquement en dehors de la base de données (et c'est souvent le cas), vous devez avoir une clé différente à cet effet. Une clé d'entreprise soigneusement sélectionnée fera l'affaire, mais vous vous retrouverez souvent dans une position d'un grand nombre de colonnes requises pour garantir l'unicité. Une autre technique consiste à avoir une colonne Id en tant que clé primaire en cluster à incrémentation automatique et une autre colonne uniqueidentifier (guid) en tant que clé unique non en cluster, dans le but d'identifier de manière unique la ligne partout où elle existe dans le monde. La raison pour laquelle vous disposez toujours d'une clé auto-incrémentée dans ce cas est qu'il est plus efficace de regrouper et d'indexer la clé auto-incrémentée que de faire de même avec un guid.
Un cas où vous ne voudrez peut-être pas une clé d'incrémentation automatique serait une table plusieurs-à-plusieurs où la clé primaire est un composé des colonnes Id de deux autres tables (vous pourriez toujours avoir une clé d'incrémentation automatique ici, mais je n'en vois pas l'intérêt).
Une autre question concerne le type de données de la clé auto-incrémentée. L'utilisation d'un Int32 vous offre une plage de valeurs large mais relativement limitée. Personnellement, j'utilise fréquemment des colonnes bigint pour l'ID, afin de ne jamais avoir à vous soucier de manquer de valeurs.
Ou existe-t-il des scénarios dans lesquels vous ne souhaitez pas ajouter un tel champ?
Sûr.
Tout d'abord, il existe des bases de données qui n'ont pas d'auto-incrémentations (par exemple, Oracle, qui n'est certainement pas l'un des plus petits concurrents). Cela devrait être une première indication que tout le monde ne les aime pas ou n'en a pas besoin.
Plus important, pensez à ce que l'ID est réellement est - c'est une clé primaire pour vos données. Si vous avez une table avec une clé primaire différente, vous n'avez pas besoin d'un ID et vous ne devriez pas en avoir un. Par exemple, une table (EMPLOYEE_ID, TEAM_ID)
(où chaque employé peut faire partie de plusieurs équipes simultanément) a une clé primaire clairement définie composée de ces deux ID. L'ajout d'une colonne d'auto-incrémentation ID
, qui est également une clé primaire pour cette table, n'aurait aucun sens. Maintenant, vous traînez 2 clés primaires, et le premier mot de la "clé primaire" devrait vous donner un indice que vous ne devriez vraiment en avoir qu'une.
J'utilise généralement une colonne "identité" (entier à incrémentation automatique) lors de la définition de nouvelles tables pour des données "à longue durée de vie" (enregistrements que je m'attends à insérer une fois et à conserver indéfiniment même s'ils finissent "supprimés logiquement" en définissant un champ de bits ).
Il y a quelques situations auxquelles je peux penser lorsque vous ne voulez pas les utiliser, la plupart se résumant à des scénarios où une table sur une instance de la base de données ne peut pas être la source faisant autorité pour les nouvelles valeurs d'ID:
Il existe des solutions de contournement qui permettent d'utiliser des colonnes d'identité dans ces situations, comme je l'espère, mais dans la plupart d'entre elles, la mise à niveau de la colonne d'identité vers un GUID est plus simple et résout le problème plus complètement.
Comme d'autres personnes ont plaidé pour une clé primaire incrémentielle, j'en ferai une pour un GUID:
Modifier: Dupliquer le point
La question et de nombreuses réponses manquent le point important que toutes les clés naturelles pour chaque table résident uniquement dans le schéma logique pour la base de données, et toutes les clés de substitution pour chaque table résident uniquement dans le schéma physique pour la base de données. d'autres réponses discutent uniquement des avantages relatifs de l'entier par rapport à GUID clés de substitution, sans discuter des raisons pour lesquelles les clés de substitution sont correctement utilisées, et quand.
BTW: Evitons d'utiliser le terme mal défini et imprécis clé primaire. Il s'agit d'un artefact de modèles de données pré-relationnels qui a d'abord été coopté (imprudemment) dans le modèle relationnel, puis réintégré dans le domaine physique par divers fournisseurs de SGBDR. Son utilisation ne sert qu'à confondre la sémantique.
Notez du modèle relationnel que, pour que la base de données schéma logique soit dans première forme normale, chaque table doit avoir un ensemble de champs visibles par l'utilisateur, connu sous le nom de clé naturelle, qui identifie de manière unique chaque ligne de la table. Dans la plupart des cas, une telle clé naturelle est facilement identifiable, mais à l'occasion, elle doit être construite, que ce soit comme un champ tie breaker ou autrement. Cependant, une telle clé construite est toujours visible par l'utilisateur et réside donc toujours dans le schéma logique de la base de données.
En revanche, tout clé de substitution sur une table réside uniquement dans le schéma physique pour la base de données (et doit donc toujours, à la fois pour des raisons de sécurité et pour la maintenance de la base de données l'intégrité, être entièrement invisible pour les utilisateurs de la base de données). La seule raison de l'introduction d'un clé de substitution est de résoudre les problèmes de performances dans la maintenance physique et utilisation de la base de données; qu'il s'agisse de jointures, de réplication, de plusieurs sources matérielles de données ou autres.
Étant donné que la seule raison de l'introduction d'une clé de substitution est la performance, supposons que nous souhaitons qu'elle soit performante. Si le problème de performance à résoudre est lié aux jointures, nous souhaitons nécessairement rendre notre clé de substitution aussi étroite que possible (sans gêner le matériel, donc les entiers et octets courts sont généralement sortis). Les performances de jointure reposent sur une hauteur d'index minimale, donc un entier sur 4 octets est une solution naturelle. Si votre problème de performances est le taux d'insertion, un entier de 4 octets peut également être une solution naturelle (selon les internes de votre SGBDR). Si votre problème de performances pour une table est la réplication ou plusieurs sources de données que d'autres technologies clé de substitution, que ce soit une GUID ou une clé en deux parties (hôte ID + entier) peut être plus approprié. Je ne suis pas personnellement un favori des GUID mais ils sont pratiques.
Pour résumer, toutes les tables n'auront pas besoin d'une clé de substitution (de tout type); ils ne doivent être utilisés que lorsqu'ils sont jugés nécessaires à la performance du tableau considéré. Quelle que soit la technologie commune clé de substitution que vous préférez, réfléchissez bien aux besoins réels de la table avant de faire un choix; changer le clé de substitution le choix technologique pour une table sera un travail épuisant. Documentez la métrique de performance clé pour votre table afin que vos successeurs comprennent les choix effectués.
Cas spéciaux
Si les exigences de votre entreprise exigent une numérotation séquentielle des transactions à des fins d'audit (ou à d'autres fins), ce champ est pas une clé de substitution; c'est une clé naturelle (avec des exigences supplémentaires). D'après la documentation, un entier auto-incrémenté ne génère que clés de substitution, alors trouvez un autre mécanisme pour le générer. Évidemment, une sorte de moniteur sera nécessaire, et si vous vous approvisionnez en transactions à partir de plusieurs sites, alors un site sera spécial, étant donné qu'il est désigné Site hôte pour le moniteur.
Si votre table ne dépassera jamais une centaine de lignes, la hauteur d'index n'a pas d'importance; chaque accès se fera par un scan de table. Cependant, les comparaisons de chaînes sur des chaînes longues seront toujours beaucoup plus chères que la comparaison d'un entier de 4 octets, et plus chères que la comparaison d'un GUID.
Un tableau de code valeurs saisies par un char (4) code champ doit être aussi performant que celui avec un octet de 4 octets entier. Bien que je n'en ai aucune preuve, j'utilise souvent cette hypothèse et je n'ai jamais eu de raison de la regretter.
En tant que principe de bonne conception, chaque table doit avoir un moyen fiable d'identifier de manière unique une ligne. Bien que ce soit à cela que sert une clé primaire, elle ne nécessite pas toujours l'existence d'une clé primaire. L'ajout d'une clé primaire à chaque table n'est pas une mauvaise pratique car elle permet une identification de ligne unique, mais elle peut être inutile.
Pour maintenir des relations fiables entre les lignes de deux tables ou plus, vous devez le faire via des clés étrangères, d'où la nécessité de clés primaires dans au moins certaines tables. L'ajout d'une clé primaire à chaque table facilite l'extension de la conception de votre base de données lorsque vient le temps d'ajouter de nouvelles tables ou relations aux données existantes. Planifier à l'avance est toujours une bonne chose.
En tant que principe de base (règle stricte peut-être), la valeur d'une clé primaire ne doit jamais changer pendant la durée de vie de sa ligne. Il est sage de supposer que toutes les données d'entreprise consécutives sont susceptibles de changer au cours de leur durée de vie, de sorte que toutes les données d'entreprise seront un mauvais candidat pour une clé primaire. C'est pourquoi quelque chose d'abstrait comme un entier auto-incrémenté est souvent une bonne idée. Cependant, les entiers auto-incrémentés ont leurs limites.
Si vos données n'ont qu'une vie dans votre base de données, les entiers auto-incrémentés conviennent. Mais, comme cela a été mentionné dans d'autres réponses, si vous souhaitez que vos données soient partagées, synchronisées ou qu'elles aient une vie en dehors de votre base de données, les entiers auto-incrémentés font de mauvaises clés primaires. Un meilleur choix sera un guid (aka uuid "id universellement unique").