Utiliser un GUID comme clé primaire

I generally use auto increment IDs as Primary Keys in databases. I am trying to learn the benefits of using GUIDs. I have read this article: https://betterexplained.com/articles/the-quick-guide-to-guids/

Je me rends compte que ces GUID sont utilisés pour identifier des objets au niveau de l'application. Sont-ils également stockés en tant que clé primaire au niveau de la base de données? Par exemple, disons que j'ai eu la classe suivante:

public class Person
{
public GUID ID;
public string Name;
..

//Person Methods follow
}

Supposons que je veuille créer une nouvelle personne en mémoire, puis l'insérer dans une base de données. Puis-je simplement faire ceci:

Person p1 = new Person();
p1.ID=GUID.NewGUID();
PersonRepository.Insert(p1);

Supposons que j'ai une base de données contenant des millions et des millions de lignes avec un GUID comme clé primaire. Cela sera-t-il toujours unique? Est-ce que je comprends même correctement les GUID?

J'ai lu cet article plus tôt: http://enterprisecraftsmanship.com/2014/11/15/cqs-with-database-généré-ids/. Cela me laisse un peu perplexe, car il semble recommander un juste milieu entre les GUID et les entiers en tant que clés primaires.

Modifier le 11/06/18

Je suis venu à croire que les guids sont plus appropriés que les ints pour mes besoins. J'utilise davantage CQRS ces temps-ci et les GUID s'intègrent plus facilement.

Je remarque que certains développeurs modélisent les GUID sous forme de chaînes dans le modèle de domaine, par exemple. ici: https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs - dans ce cas: IdentityGuid est un modèle GUID, car un string. Existe-t-il une raison autre que celle indiquée ici: Utiliser un objet de valeur personnalisé ou un GUID en tant qu'identificateur d'entité dans un système distribué? . Est-il "normal" de modéliser le GUID en tant que chaîne ou devrais-je le modéliser en tant que GUID dans le modèle et la base de données?

31
Je suis venu à croire que les Guids sont plus adaptés que les ints pour mes besoins. Je dis que le GUID est un dernier recours (et int d'ailleurs). L'indexation est inutile, et énigmatique, au mieux, dans les requêtes. OTOH, les clés composées sont DSL-ish en utilisation, contextuelles, descriptives, flexibles et importantes pour la performance. Les requêtes sur un sous-ensemble d'une PC composée peuvent l'utiliser. Je mets en garde contre la création de pharmacocinétiques pour elle-même - là où rien n’est justifié. Rien ne se passe mal avec l'indexation nécessaire sur les tables non PK'ed. Les PC communiquent intrinsèquement la structure des données, les relations et les exigences.
ajouté l'auteur jbu, source
Le système sur lequel je travaille en ce moment utilise des UUID. Une propriété intéressante est qu'un identifiant identifie de manière unique un enregistrement, par opposition à un identifiant séquentiel qui identifie un enregistrement dans cette table.
ajouté l'auteur Bakhtiyor, source
@ w0051977 ils ne le font pas, mais cela peut aider - j'ai vu des systèmes (certes mal codés) dans lesquels un RoleId était utilisé de manière incorrecte en tant que UserRoleId - et dans dev environnements cela a même fonctionné, car l’ID 1 fonctionnait dans les deux cas. Avec les UUID, les identifiants seraient différents.
ajouté l'auteur Bakhtiyor, source
Double possible de UUID vs Integer
ajouté l'auteur gnat, source
voir aussi: Collisions d'UUID
ajouté l'auteur gnat, source
ajouté l'auteur Euphoric, source
Voir aussi dba.stackexchange.com/questions/54690/… , ainsi que de nombreuses autres questions (ce sujet a été posé, et a répondu, et a discuté à propos de, souvent.
ajouté l'auteur Arash, source
Il n'est pas garanti que ce soit unique, bien qu'il soit peu probable que vous assistiez à une collision. stackoverflow.com/questions/1155008/how-unique- is-uuid/& hellip;
ajouté l'auteur icirellik, source
@ Justin, pourquoi les enregistrements doivent-ils être uniques dans plusieurs tables?
ajouté l'auteur w0051977, source

10 Réponses

Les GUID sont par définition des "identifiants globaux uniques". Il existe en Java un concept similaire mais légèrement différent appelé UUID "Universally Unique IDentifiers". Les noms sont interchangeables pour toute utilisation pratique.

Les GUID jouent un rôle central dans la manière dont Microsoft envisageait le clustering de bases de données. Si vous devez incorporer des données provenant de sources parfois connectées, ils contribuent réellement à éviter les collisions de données.

Quelques faits sur le Pro-GUID:

  • Les GUID empêchent les collisions de clés
  • Les GUID aident à la fusion de données entre réseaux, machines, etc.
  • SQL Server prend en charge les GUIDS semi-séquentiels pour aider à réduire la fragmentation des index ( ref , quelques mises en garde)

Un peu de laideur avec des GUID

  • Ils sont gros, 16 octets chacun
  • Ils sont en panne, vous ne pouvez donc pas trier par ID et espérez obtenir l'ordre d'insertion comme vous pouvez le faire pour les identifiants à incrémentation automatique
  • Ils sont plus encombrants, en particulier pour les petits ensembles de données (comme les tables de consultation)
  • La nouvelle implémentation de GUID est plus robuste sur SQL Server que dans la bibliothèque C# (vous pouvez avoir GUIDS séquentiel à partir de SQL Server, en C#, il est aléatoire)

Les GUID augmenteront la taille de vos index, de sorte que le coût de l'espace disque lié à l'indexation d'une colonne sera plus élevé. Les GUID aléatoires vont fragmenter vos index.

Si vous savez que vous n'allez pas synchroniser les données de différents réseaux, les GUID peuvent générer plus de temps système que nécessaire.

Si vous avez besoin d'ingérer des données à partir de clients parfois connectés, elles peuvent être beaucoup plus robustes pour éviter les collisions clés que de compter sur la définition de plages de séquences pour ces clients.

39
ajouté
J'ai créé cette communauté WIKI et enlevé les déclarations les plus controversées. Ayez et faites la réponse la plus correcte. J'ai l'impression que je suis sur la bonne voie, mais qu'il me manque quelques points clés.
ajouté l'auteur tim_yates, source
Tout comme moi. Merci pour les commentaires, j'ai appris quelques choses.
ajouté l'auteur tim_yates, source
Il y a aussi cette information qui peut aussi aider: blog.codinghorror.com/primary -keys-ids-versus-guids (vous pouvez avoir des GUID séquentiels dans SQL Server séquentiels pour chaque ordinateur sur lequel il est allumé)
ajouté l'auteur tim_yates, source
Voici quelques informations: blogs.msdn.microsoft .com/sqlserverfaq/2010/05/27/& hellip; J'admets que certaines de mes informations concernant les GUID et la mise en cluster de SQL Server sont anciennes. Certaines choses changent et certaines choses restent les mêmes (par exemple, SQL Server ne prend en charge que le clustering avec basculement au cours des dernières années).
ajouté l'auteur tim_yates, source
@ JimmyJames, la balise étant destinée à SQL Server, j'ai adapté la réponse à cette question. Oracle n'a jamais été vraiment construit autour de GUID ou UUID, votre expérience ne me surprend donc pas.
ajouté l'auteur tim_yates, source
"Ils sont en panne, vous ne pouvez donc pas trier par ID et espérer obtenir l'ordre d'insertion comme vous le pouvez pour les identifiants à incrémentation automatique" Franchement, je ne suis pas à l'aise avec cela avec des identifiants normaux non plus. Bien qu'il soit possible dans un cas extrême d'extrême limite pour un identifiant inférieur de s'engager sur le disque plus tard, je préfère me fier à des données de tri utiles, telles qu'un horodatage d'insertion. Les identifiants doivent être traités comme des adresses de mémoire: tout en a un, mais la valeur elle-même n'a pas de sens. Utilisez-les au maximum pour les bris d'égalité. D'autant que si vous avez un chargement en masse, l'ordre d'insertion n'est pas garanti.
ajouté l'auteur Hao Sun, source
@ MaxVernon "N'est pas optimal" est un euphémisme énorme.
ajouté l'auteur Andy, source
"SQL Server dispose d'optimisations pour traiter les GUID, il ne devrait donc pas trop affecter les performances des requêtes." -1 Pas assez optimisé. Je travaille avec une base de données où toutes les PC sont des guids, et c'est l'une des principales causes de mauvaises performances.
ajouté l'auteur Andy, source
"SQL Server dispose d'optimisations pour traiter avec les GUID . Les performances de la requête ne devraient donc pas trop affecter. " Faux. Cette déclaration suppose que d'autres types de données ne sont pas optimisés. Les serveurs de base de données disposent également d’optimisations permettant de traiter des valeurs simples, par exemple. Les GUID/UUID sont beaucoup plus lents que d'utiliser une valeur int de 4 octets. 16 octets ne seront jamais aussi rapides que 4 octets - en particulier sur une machine gérant au plus 4 ou 8 octets en mode natif.
ajouté l'auteur user192127, source
@CortAmmon Selon Wikipedia et RFC 4122 , ils sont synonymes. P. Leach de Microsoft était l'un des créateurs de la RFC. Je pense que depuis la création de la RFC, les deux sont identiques. Extrait du RFC: "UUID (Universally Unique IDentifier), également appelé GUID (Globally Unique IDentifier)." Je pense qu'il est également utile de noter que les GUID n'ont pas été créés par MS. Ils viennent de créer un nouveau nom pour une technologie adoptée d’ailleurs.
ajouté l'auteur JimmyJames, source
@MartinSmith Je pense que le fait est que l'ID interne de la ligne dans la base de données est un GUID. C'est la même chose pour Oracle, mais je ne suis pas sûr que la base de données l'utilise nécessairement dans toutes les recherches.
ajouté l'auteur JimmyJames, source
@MartinSmith Cela ne fait pas partie de mes compétences, mais la page wikipedia UUID semble pertinent.
ajouté l'auteur JimmyJames, source
@MartinSmith C'est une information utile, mais je ne suis pas un fan de cela, comme indiqué dans divers commentaires ici.
ajouté l'auteur JimmyJames, source
Je crois comprendre que les GUID sont synonymes d’UUID. UUID est le nom standard. Le GUID est ce que Microsoft les a inventé avant la RFC 4122 .
ajouté l'auteur JimmyJames, source
Oui, je dis simplement que c'est une bonne idée de vraiment bien comprendre quels compromis pourraient être impliqués avec cela. Vous en avez mentionné quelques-unes, je ne saurais pas si c'est complet. Dans notre cas, nous utilisions les identifiants de ligne «natifs» en tant que PK. Donc, bien que je convienne qu'Oracle ne gère pas bien cela, il est en fait "construit" autour de cela. Comme c'est du 128 bits, au moins, en 2017, vous obligez la base de données à utiliser plus d'un registre par clé.
ajouté l'auteur JimmyJames, source
+1 et je vous recommande de lire les petits caractères sur la façon dont la base de données les gère. Nous l'avons fait dans Oracle et cela s'est très mal passé. Les requêtes devaient être peaufinées de manière obscure pour atteindre l'index. L’autre problème (IIRC) est que les GUID générés sur la même machine à peu près au même moment tendent à être identiques au début et à la fin, mais différents au milieu. Vous avez donc besoin d’une stratégie d’indexation spéciale pour gérer cette situation, en particulier très grande plage de potentiel.
ajouté l'auteur JimmyJames, source
@ MaxVernon est-ce la raison pour laquelle certains suggèrent la combinaison pile/GUID?
ajouté l'auteur Mark Maruska, source
@ ypercubeᵀᴹ - Je suppose que c'est un moyen de "contourner" le problème de la fragmentation des tables. Bien que cela ne soit qu'un échange de problème. Les tas ne servent à rien, sauf si vous pouvez fréquemment les TRUNCATE TABLE .
ajouté l'auteur Geocode.Farm Staff, source
Si Mme Tripp dit que c’est vrai, c’est absolument vrai .
ajouté l'auteur Geocode.Farm Staff, source
Moi aussi, je suis intéressé par la différence entre les GUID et les UUID. Les réponses comme celles-ci suggèrent de les traiter synonyme, mais Stack Exchange est une source loin d'être définitive /canards
ajouté l'auteur Cort Ammon, source
GUID et UUID sont devenus synonymes. Essayer de les traiter différemment va semer la confusion chez les gens un peu plus loin.
ajouté l'auteur icirellik, source

Cela sera-t-il toujours unique?

Always? no, not always; it's a finite sequence of bits.

Disons que j'avais une base de données contenant des millions et des millions de lignes avec un GUID comme clé primaire.

Des millions et des millions, vous êtes probablement en sécurité. Un million de millions de personnes et la probabilité d'une collision devient importante. La bonne nouvelle cependant: vous n’avez déjà plus assez d’espace disque.

Puis-je simplement faire cela?

Vous pouvez; ce n'est pas une très bonne idée. Votre modèle de domaine ne devrait normalement pas générer de nombres aléatoires; ils devraient être des entrées dans votre modèle.

Au-delà de cela, lorsque vous traitez avec un réseau peu fiable, dans lequel vous pouvez obtenir des messages en double, un UUID généré par de manière déterministe vous protégera des entités en double. Mais si vous attribuez un nouveau nombre aléatoire à chacun, vous aurez plus de travail à faire pour identifier la duplication.

See the description of name-based uuid in RFC 4122

Est-il "normal" de modéliser le GUID en tant que chaîne ou devrais-je le modéliser en tant que GUID dans le modèle et la base de données?

Je ne pense pas que cela compte beaucoup. Pour la plupart de votre modèle de domaine, il s'agit d'un identifiant ; la seule question que vous posez est de savoir s'il est identique ou non à un autre identifiant. Votre modèle de domaine ne regarde normalement pas la représentation en mémoire d'un identifiant.

Si le GUID est disponible en tant que "type primitif" dans votre paramètre agnostique de domaine, je l’utiliserais; cela permet au contexte de support de choisir les optimisations appropriées pouvant être disponibles.

Ce que vous devez reconnaître, cependant, c’est que la représentation de l’identificateur, à la fois en mémoire et en stockage, est une décision que vous prenez dans votre implémentation. Par conséquent, vous devez prendre des mesures pour vous assurer que l’empreinte de code associée à cette la décision est petite - voir Parnas 1972 .

25
ajouté
Un million millions = 2 ^ 40. Cela fait 2 ^ 79 paires de collisions possibles. Le GUID a 2 ^ 128 bits, la probabilité est donc de un sur 2 ^ 49. Il est beaucoup plus probable que vous ayez un bogue qui réutilise le même GUID pour deux enregistrements ou qui croit à tort qu'il existe une collision où il n'y en a pas.
ajouté l'auteur gnasher729, source
En effet, pouvoir recalculer un UUID/GUID à partir d'autres données est une aide précieuse, en particulier pour détecter les doublons. Une fois, j'ai construit un système de traitement de messages qui stockait les messages et les faisait passer par un pipeline de traitement. J'ai créé un hachage du message et je l'ai utilisé comme clé primaire dans tout le système. En soi, cela m'a résolu BEAUCOUP de problèmes pour identifier le message lorsque nous devions passer à la vitesse supérieure.
ajouté l'auteur Newtopian, source
Je pense que le concept de " UUID généré de manière déterministe " est essentiel (voir Data Vault 2)
ajouté l'auteur peterd, source
Peut-être que ces développeurs avaient besoin d'optimiser leurs compromis différemment.
ajouté l'auteur VoiceOfUnreason, source
Merci. Juste pour que je sois clair; la réponse suggère un GUID dans le modèle de domaine (C #) et un identificateur unique (plutôt qu'un varchar) dans la base de données (SQL Server). Je remarque que cela diffère de ce qui se trouve ici: github.com/dotnet-architecture/eShopOnContainers/blob/dev/sr‌ c/& hellip;
ajouté l'auteur w0051977, source
Je reviens sur mes questions historiques. Avant que j'accepte Pourriez-vous jeter un oeil à mon édition?
ajouté l'auteur w0051977, source
+1 pour "vous êtes déjà à court d'espace disque au moment où cela se produit".
ajouté l'auteur w0051977, source

Le GUID ou UUID sera très probablement unique en raison de la manière dont elles sont générées et offrent un moyen sûr de garantir l'unicité sans avoir à communiquer avec une autorité centrale.

Avantages des GUID en tant que clé primaire:

  • Vous pouvez copier des données entre différents fragments d'un cluster sans avoir à vous soucier des collisions PK.
  • Il vous permet de connaître votre clé primaire avant d'avoir inséré des enregistrements.
  • Simplifie la logique de transaction pour l'insertion d'enregistrements enfants.
  • Ne peut être facilement deviné.

Dans l'exemple que vous avez fourni:

Person p1 = new Person();
p1.ID = GUID.NewGUID();
PersonRepository.Insert(p1);

La spécification du GUID avant le temps d'insertion peut enregistrer un aller-retour vers la base de données lors de l'insertion d'enregistrements enfant successifs et vous permettre de les valider dans la même transaction.

Person p2 = new Person();
p2.ParentID = p1.ID
PersonRepository.Insert(p2);

Détérioration des GUID en tant que clé primaire:

  • Ils ont une taille de 16 octets, ce qui signifie qu'ils consommeront plus d'espace à mesure que des index et des clés étrangères sont ajoutés.
  • Ils ne trient pas bien car ce sont essentiellement des nombres aléatoires.
  • L'utilisation de l'index est très, très, très mauvaise.
  • Beaucoup de feuilles en mouvement.
  • Ils sont difficiles à retenir.
  • Ils sont difficiles à verbaliser.
  • Ils peuvent rendre les URL plus difficiles à lire.

Si votre application n'a pas besoin de partage ou de clustering, il est préférable de s'en tenir à des types de données plus petits et plus simples tels que int ou bigint.

De nombreuses bases de données ont leurs propres implémentations internes qui tentent d'atténuer les problèmes de stockage causés par les GUID. SQL Server a même une fonction newsequentialid pour aider à la commande des UUID permettant une meilleure utilisation des index et dont les performances sont généralement meilleures.

De plus, du point de vue d'un testeur, d'un utilisateur ou d'un développeur travaillant avec l'application, l'utilisation d'un ID sur un GUID améliorera considérablement la communication. Imaginez avoir à lire un GUID sur un téléphone.

En fin de compte, sauf si la mise en cluster ou l'obscurcissement d'URL à grande échelle est une exigence, il est plus pragmatique de s'en tenir à des ID auto-incrémentés.

10
ajouté
@mirabilos Fon, l'utilisation d'une sorte d'algorithme Hi-Lo au niveau thread-local serait une solution plus simple, à mon humble avis, et vous obtiendrez tout de même des ID plus petits et essentiellement séquentiels.
ajouté l'auteur David Nehme, source
@mirabilos De plus, je ne recommanderais pas l'utilisation de clés 128 bits dans Oracle. Voir mon commentaire sur la réponse de Berin. Les performances autour de ce type de PK dans Oracle peuvent être redoutables si vous ne faites pas les déductions nécessaires.
ajouté l'auteur JimmyJames, source
@mirabilos Je serais intéressé à comprendre comment/quand cela ne peut pas être résolu en augmentant la taille du bloc de séquence.
ajouté l'auteur JimmyJames, source
J'ai peut-être mal compris. J'ai supposé "Ils peuvent rendre l'URL plus difficile à lire." implicite qu'ils seraient utilisés là-bas. Je ne suis pas sûr de convenir qu'en général, utiliser la clé dans l'URI pose forcément toujours un problème, mais il est tout à fait possible.
ajouté l'auteur JimmyJames, source
@mirabilos Pour être clair, quand je dis terrible, nous avons fini par avoir des insertions qui prenaient minutes par rangée. Tout a commencé comme prévu, mais après des dizaines de milliers de lignes, tout a été très rapide. Si ce n'est pas évident, une dizaine de milliers de lignes est une très petite table.
ajouté l'auteur JimmyJames, source
Une chose à considérer est que, selon le type de UUID , ils contiennent potentiellement des informations utilisé pour identifier la machine sur laquelle ils sont générés. La variante purement aléatoire peut être plus susceptible d'entrer en collision sans entropie suffisante. Cela devrait être pris en compte avant utilisation dans un URI.
ajouté l'auteur JimmyJames, source
La principale raison de leur utilisation est qu’un GUID en tant que clé d’index cluster entraînera une fragmentation importante, contrairement au GUID séquentiel. Cela présente des avantages en termes de performances ainsi que des problèmes de sécurité, tels que la prévisibilité.
ajouté l'auteur icirellik, source
D'accord, même s'il ne faut jamais exposer sa clé primaire dans une URL. Une méthode plus appropriée devrait être utilisée pour éviter toute fuite de données sécurisée vers un système externe.
ajouté l'auteur icirellik, source
Si vous utilisez newsequentialid, vous devez vous rendre sur la base de données pour obtenir l'identifiant (comme avec une identité int), n'est-ce pas? Quel est l'avantage ici.
ajouté l'auteur w0051977, source
Un autre cas d’utilisation: les bases de données OLTP à insert volumineux dans lesquelles le verrouillage de la séquence est un goulot d’étranglement. Selon mon ami administrateur DBA d’Oracle, ce n’est pas aussi rare que cela puisse paraître, vous n’avez même pas besoin d’une grande échelle ou de clusters pour cela. • En fin de compte, pesez le pour et le contre (et ne confondez pas le pour/le contre des UUID avec des pour/contre qui ne sont pas spécifiques aux UUID comme le font certaines affiches) et la mesure .
ajouté l'auteur mirabilos, source
Vous pouvez "aider" la fragmentation en générant une valeur "semblable à un guide séquentiel" côté client (en C# par exemple). UDPCAD -000CF1ADC5B7 voir pinvoke.net/default.aspx/rpcrt4.UuidCreateSrential
ajouté l'auteur granadaCoder, source

Je dirais non, n'utilisez pas de GUID en tant que clés primaires. En fait, je traite actuellement d’une telle base de données, qui est l’une des principales causes des problèmes de performances.

Les 12 octets supplémentaires s’ajoutent rapidement; Rappelez-vous que la plupart des PK sont des FK dans d'autres tables, et que sur trois FK d'une table, vous disposez maintenant de 48 octets supplémentaires pour chaque ligne. Cela s’ajoute dans la table et dans les index. Il ajoute également dans les E/S de disque. Ces 12 octets supplémentaires doivent être lus et écrits.

Et si vous n'utilisez pas d'instructions séquentielles et que les PC sont regroupées (ce qui se produit par défaut), SQL devra de temps en temps déplacer des pages de données entières pour en insérer davantage dans le "point" correct. Pour une base de données hautement transactionnelle comportant de nombreuses insertions, mises à jour et suppressions, les choses s'enlisent rapidement.

Si vous avez besoin d'un identifiant unique pour la synchronisation ou autre, ajoutez une colonne guid. Juste n'en fais pas le PK.

4
ajouté

Je me rends compte que ces GUID sont utilisés pour identifier des objets au niveau de l'application. Sont-ils également stockés en tant que clé primaire au niveau de la base de données?

C'est là que vous devriez vous arrêter, là-bas, et repenser.

Votre clé primaire de base de données ne doit JAMAIS avoir de signification commerciale. Cela ne devrait pas avoir de sens par définition.

Ajoutez donc le GUID en tant que clé d'entreprise et une clé primaire normale (généralement un long entier) en tant que clé primaire de la base de données. Vous pouvez toujours mettre un index unique sur le GUID pour garantir l'unicité.

Cela parle bien sûr de la base de données, mais c'est aussi une bonne pratique. Je me suis occupé de bases de données dont les clés primaires avaient une signification (un client avait pensé économiser certaines ressources de la base de données en les utilisant comme numéros d'employé, numéros de client, etc., par exemple) et cela posait toujours problème.

2
ajouté
@icirellik, la clé primaire est destinée à un usage interne par la base de données, pour lier les enregistrements parent et enfant, etc. Ce n'est pas destiné à être utilisé par la logique d'application, vous utilisez des identifiants professionnels, comme un numéro de produit ou un nom.
ajouté l'auteur jwenting, source
En quoi cela diffère-t-il de l'interrogation de la couche d'application à l'aide d'une clé primaire entière? À ce stade, il est également utilisé pour identifier des objets au niveau de la couche d'application. Vous avez besoin d'un moyen d'identifier les objets d'une base de données à partir de la couche d'application.
ajouté l'auteur icirellik, source

Toujours utiliser les clés primaires (PKs) générées par la base de données et auto-incrémentées.

Pourquoi utiliser l'auto-incrémentation au lieu de GUID/UUID?

  • Les GUID (UUID) n’empêchent pas les collisions de clés car elles ne sont pas uniques et il n’existe aucun moyen de les rendre uniques car elles sont générées à partir de nombreuses sources.
  • Les GUID n’aident pas à la fusion, car ils augmentent considérablement le processus de fusion, qui prend déjà beaucoup de temps, avec des colonnes PK et FK extrêmement longues et non entières qui prennent beaucoup de temps à traiter. Rappelez-vous que pour la plupart des PK, il y aura au moins une autre table avec au moins 2 clés de la même taille: il s'agit de votre propre PK et d'un FK vers la première table. Tous doivent être résolus en une fusion.

Mais comment alors gérer des fragments, des clusters, etc.?

  • Créez des PK à plusieurs colonnes constituées de colonnes distinctes identifiant chaque fragment, cluster, base de données ou tout autre outil gérant ses propres clés à incrémentation automatique. Par exemple ...

Une clé publique à trois colonnes pour une table en cluster peut être ...

 DB | SH | KEY     |
----|----|---------|
 01 | 01 | 1234567 |

Mais qu'en est-il ...?

  • Déplacements multiples dans la base de données - La plupart des applications n'ont pas besoin d'identifier de manière unique un enregistrement en cours de création jusqu'à ce qu'il soit inséré dans la base de données car ce thread/cette session/ce qui ne fonctionne que sur un à la fois. Si l’application a vraiment besoin de cette possibilité, utilisez une PK temporaire générée par l’application, qui n’est pas envoyée à la base de données . Laissez la base de données mettre ensuite sa propre PK à incrémentation automatique sur la ligne lorsqu'elle est insérée. Les inserts utiliseront le PK temporaire, tandis que les mises à jour et les suppressions utiliseront le PK permanent attribué par la base de données.

  • Performances - Les ordinateurs peuvent traiter des entiers simples beaucoup plus rapidement que toute autre chose, en raison du domaine considérablement plus grand, si les valeurs possibles par élément d'un GUID (37) sont comparées à un entier (10). N'oubliez pas non plus que chaque caractère d'un GUID doit d'abord être converti en un nombre à manipuler par la CPU.

Common Misuses of Primary Keys PKs have only one purpose... to absolutely uniquely identify a row in a table. Anything else is an all-too-common misuse.

Détecter les enregistrements manquants

  • Missing records cannot be detected by looking at the PKs. Bless QA for at least attempting to ensure data quality. However, they and programmer's lack of understanding of how keys in modern database systems are assigned often leads them to the misbelief that a missing number in an auto-incrementing PK means missing data. It does not because...
  • For performance, database systems allocate blocks of numbers in 'sequences'(batches, ranges) to minimize trips to the actual database in storage. The size of these sequences of numbers is often under the control of the DBA but may not be tunable on a per-table basis.
  • The key takeaway is... unused numbers from these sequences are never returned to the database so there are always gaps in the PK numbers.
  • Why would there be unused numbers you ask? Because a variety of database maintenance actions may cause sequences to be abandoned. These are things like restarts, bulk reloads of tables, some types of restoration from backups and some other operations.

Tri

  • Tri by PK is very error-prone since most people will think it lists the rows in the order they were created and that that corresponds to clock time. Mostly, but not necessarilly.
  • Database engines are optimized for maximum performance and that may mean delaying insert of the results of a long-running complicated transaction in order to insert short simple ones, "out-of-turn" so to speak.
2
ajouté
@RibaldEddie - Pour ce que la base de données est conçue pour permettre ... absolument. Les suppressions sont faciles. Lorsque votre scénario se produit, je considère qu’un bogue doit être corrigé dans le logiciel, puis supprimer l’une ou l’autre ligne. Le cas le plus courant est cependant deux enregistrements pour la même chose avec des données légèrement différentes, ils doivent donc être fusionnés. Si une colonne est vide dans un enregistrement et a une valeur dans l'autre, le choix est évident et peut être automatisé. Souvent, l'horodatage peut être utilisé pour arbitrer une fusion automatisée. Certains doublons obligent une personne à terminer et à vérifier la fusion en fonction de règles commerciales.
ajouté l'auteur yaplik, source
J'ai ajouté beaucoup plus à la réponse dans ce sens. La réponse originale était incomplète à cause de l'application Android SE sur laquelle je suis suspendu. Je pense qu'une réécriture majeure de l'application est en cours de développement.
ajouté l'auteur yaplik, source
Donc, à votre avis, il serait normal qu'une table contienne un nombre quelconque de lignes identiques, à l'exception de leur clé primaire auto-incrémentée?
ajouté l'auteur Unknown Zombie, source
Que pensez-vous du schéma de table pour que la seule colonne unique soit une clé primaire auto-incrémentée créée par la base de données? En particulier pour les tables qui n'ont pas de clé étrangère mais dont la clé primaire est la clé étrangère pour plusieurs tables liées?
ajouté l'auteur Unknown Zombie, source
Person p1 = new Person();
p1.ID=GUID.NewGUID();
PersonRepository.Insert(p1);

C’est de loin la raison la plus importante pour l’utilisation des GUID.

Le fait que vous puissiez créer un identifiant unique sans que votre code connaisse votre couche de persistance ni ne communique avec vous constitue un avantage considérable.

Vous pouvez être sûr que l’objet Personne que vous venez de générer sur votre serveur, votre téléphone, votre ordinateur portable, votre périphérique hors ligne ou autre est unique sur tous vos serveurs, quel que soit le type de distribution.

Vous pouvez le coller dans n’importe quel type de base de données rdb ou no-sql, le classer, l’envoyer à n’importe quel service Web ou le jeter immédiatement, sans rien modifier.

Non, vous n'obtiendrez jamais de collision.

Oui, les insertions peuvent être légèrement plus lentes car il peut être nécessaire de manipuler l’index.

Oui, il est plus gros qu'un int.

  • modifier. dû partir avant de finir.

Je sais que beaucoup de gens sont très attachés aux technologies de l'automobile et il s'agit d'un sujet controversé avec les administrateurs de bases de données.

Mais je ne peux vraiment pas dire assez clairement à quel point les joueurs sont supérieurs. Vous devez utiliser des guids par défaut dans n'importe quelle application.

auto inc ints ont beaucoup de défauts

  • Vous utilisez une base de données distribuée No-Sql. Vous ne pouvez simplement pas parler à toutes les autres instances pour savoir quel est le prochain numéro.

  • Vous utilisez un système de file d'attente de messages. Les choses nécessitent des identifiants avant d’atteindre la base de données

  • Vous créez plusieurs éléments et les modifiez avant de les enregistrer. Chacun a besoin d'un identifiant avant d'avoir touché la base de données

  • Vous souhaitez supprimer et réinsérer des lignes. Veillez à ne pas compter vos identifiants d'incident automatique et à ne pas manquer!

  • Vous ne souhaitez pas exposer le nombre de commandes que vous avez prises cette année à chaque utilisateur

  • Vous souhaitez déplacer des données anonymisées de la production pour les tester et conserver les relations intactes. Mais ne supprimez pas toutes les données de test existantes.

  • Vous souhaitez fusionner votre produit à locataire unique dans une base de données à locataires multiples, mais tout le monde a une commande 56.

  • Vous créez des objets persistants mais éphémères. (commandes incomplètes) encore une fois, n'utilisez pas toutes vos ressources avec des choses qui n'existent plus.

La liste est interminable et ce sont tous des problèmes réels qui se posent tout le temps aux gens. contrairement à manquer d'espace disque en raison de cols FK légèrement plus grandes

Enfin, l’immense problème avec les ints est que vous en manquez !!! ok en théorie vous ne faites pas, il y a des charges. Mais en pratique, vous le faites parce que les gens ne les traitent pas comme des nombres aléatoires sans signification. ils font des choses comme

  • oh, je ne veux pas que les clients pensent que nous sommes nouveaux. commencer à 10 000

  • Je devais importer une charge de données afin que je sois juste à 1m de la graine afin que nous sachions ce qui est importé

  • nous avons besoin de catégories de données. chaque période commence au million suivant afin que nous puissions utiliser les premiers chiffres comme un nombre magique

  • J'ai supprimé et réimporté toutes les données avec de nouveaux identifiants. Oui, même les journaux d’audit.

  • utilisez ce numéro, qui est une clé composite, comme identifiant de cet autre objet

2
ajouté
Cela dépend de ce que vous entendez par "entrer en collision". Dans la même table, la probabilité d'une collision automatique auto est égale à zéro.
ajouté l'auteur sgwill, source
Je pense qu'il y aura quelques applications étranges où les guides sont meilleurs. Unique n'est pas la chose la plus importante à considérer. Vos "défauts" d'ints sont massivement exagérés, et vous ne considérez aucun des nombreux inconvénients des écrans.
ajouté l'auteur Andy, source
-1 pour "Vous devez utiliser des guides par défaut dans n'importe quelle application." Ça dépend. Et comme d'autres l'ont montré, les GUID/UUID ne sont absolument pas garantis d'être uniques.
ajouté l'auteur Geocode.Farm Staff, source
Les réponses "ça dépend" sont inutiles, bien qu'il y ait des applications étranges où un int est meilleur. Mais les chances sont que votre application n'est pas l'un d'eux. Les GUID sont la chose la plus unique que vous puissiez obtenir
ajouté l'auteur Ewan, source
il est plus probable qu'un auto inc int va entrer en collision qu'un guid
ajouté l'auteur Ewan, source
ce n'est tout simplement pas vrai. vous pouvez facilement obtenir une collision int en insérant simplement une valeur supérieure à la valeur d'origine ou en réinitialisant cette valeur à une valeur inférieure
ajouté l'auteur Ewan, source
Cette réponse n’a rien d’inconvénient factuel, mais j’aimerais (pour parer à d’autres votes négatifs) peut-être préciser explicitement que si les applications réelles ne rencontrent pas de collision, elles sont théoriquement possibles. (Ou peut-être plus de 45 bases de données exabyte sont plus répandues que je ne le pensais ...). Bien que je pense que le langage "la raison la plus importante" est un peu fort, c'est ce que je trouve le plus utile.
ajouté l'auteur Pascalerino, source

Comme pour toute chose, cela présente des avantages et des inconvénients:

Le bon:

  1. Vos clés ont toujours la même longueur (les très grandes bases de données peuvent avoir de très grandes clés)

  2. L'unicité est quasiment garantie - même lorsque vous les générez à partir d'un système séparé et/ou que vous n'avez pas lu le dernier ID de la base de données

Le mauvais:

  1. Comme mentionné plus haut - des index plus importants et un magasin de données.

  2. Vous ne pouvez pas commander par ID, vous devez commander par autre chose. Plus d'index, probablement moins efficace.

  3. Ils sont moins lisibles par l'homme. Les entiers sont généralement plus faciles à analyser, à mémoriser et à taper pour les personnes. L'utilisation de GUID comme identifiants dans les clauses WHERE dans plusieurs tables jointes peut faire fondre votre tête.

Comme pour tout, utilisez-les le cas échéant, ne soyez pas dogmatiques - dans de nombreuses situations, les entiers auto-incrémentés sont meilleurs, parfois les GUID sont géniaux.

1
ajouté

Oui, vous pouvez utiliser le GUID comme clé primaire. L'inconvénient est la taille et la fragmentation rapide de l'indice.

Sauf si vous avez besoin d'unicité parmi les bases de données (par exemple un cluster), un nombre entier est préférable.

0
ajouté
Les générateurs de GUID peuvent produire le même GUID plus d’une fois, c’est là un défaut. Qu'ils le veuillent ou non, cela dépend de leur granularité, principalement de l'intervalle entre les impulsions d'horloge. Par exemple. un générateur basé sur une horloge ne peut tourner que toutes les 100 ms, ce qui donne lieu à deux GUID demandés dans les 100 ms sur cet ordinateur étant identiques. La plupart du temps, il existe des moyens d'éviter cela, mais de nombreux générateurs GUID fonctionnent entièrement en dehors de l'adresse IP et/ou MAC et de l'horodatage.
ajouté l'auteur jwenting, source

Voici mon point de vue sur cette question - la solution est un compromis entre les valeurs de GUID et de int, en prenant le meilleur des deux.

La classe génère une valeur d'identifiant pseudo aléatoire (mais croissante dans le temps), similaire à une valeur GUID de peigne .

Le principal avantage est qu'il permet de générer des valeurs Id sur le client, plutôt que d'utiliser des valeurs auto-incrémentées générées sur le serveur (ce qui nécessite un aller-retour) avec un risque presque nul de doublons.

Les valeurs générées utilisent uniquement 8 octets au lieu de 16 pour un GUID et ne dépendent pas d'un ordre de tri de base de données spécifique (par exemple, Sql Server pour les GUID ). Les valeurs pourraient être étendues pour utiliser toute la plage longue non signée, mais cela poserait des problèmes avec toute base de données ou tout autre référentiel de données comportant uniquement des types entiers signés.

public static class LongIdGenerator
{
   //set the start date to an appropriate value for your implementation 
   //DO NOT change this once any application that uses this functionality is live, otherwise existing Id values will lose their implied date
    private static readonly DateTime PeriodStartDate = new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    private static readonly DateTime PeriodEndDate = PeriodStartDate.AddYears(100);
    private static readonly long PeriodStartTicks = PeriodStartDate.Ticks;
    private static readonly long PeriodEndTicks = PeriodEndDate.Ticks;
    private static readonly long TotalPeriodTicks = PeriodEndTicks - PeriodStartTicks;

   //ensures that generated Ids are always positve
    private const long SEQUENCE_PART_PERMUTATIONS = 0x7FFFFFFFFFFF; 

    private static readonly Random Random = new Random();

    private static readonly object Lock = new object();
    private static long _lastSequencePart;

    public static long GetNewId()
    {
        var sequencePart = GetSequenceValueForDateTime(DateTime.UtcNow);

       //extra check, just in case we manage to call GetNewId() twice before enough ticks have passed to increment the sequence 
        lock (Lock)
        {
            if (sequencePart <= _lastSequencePart)
                sequencePart = _lastSequencePart + 1;

            _lastSequencePart = sequencePart;
        }

       //shift so that the sequence part fills the most significant 6 bytes of the result value
        sequencePart = (sequencePart << 16);

       //randomize the lowest 2 bytes of the result, just in case two different client PCs call GetNewId() at exactly the same time
        var randomPart = Random.Next() & 0xFFFF;

        return sequencePart + randomPart;
    }

   //used if you want to generate an Id value for a historic time point (within the start and end dates)
   //there are no checks, compared to calls to GetNewId(), but the chances of colliding values are still almost zero
    public static long GetIdForDateTime(DateTime dt)
    {
        if (dt < PeriodStartDate || dt > PeriodStartDate)
            throw new ArgumentException($"value must be in the range {PeriodStartDate:dd MMM yyyy} - {PeriodEndDate:dd MMM yyyy}");

        var sequencePart = GetSequenceValueForDateTime(dt.ToUniversalTime());
        var randomPart = Random.Next() & 0xFFFF;
        return ( sequencePart << 16 ) + randomPart;
    }

   //Get a 6 byte sequence value from the specified date time - startDate => 0 --> endDate => 0x7FFFFFFFFFFF
   //For a 100 year time period, 1 unit of the sequence corresponds to about 0.022 ms
    private static long GetSequenceValueForDateTime(DateTime dt)
    {
        var ticksFromStart = dt.ToUniversalTime().Ticks - PeriodStartTicks;
        var proportionOfPeriod = (decimal)ticksFromStart/TotalPeriodTicks;
        var result = proportionOfPeriod * SEQUENCE_PART_PERMUTATIONS;
        return (long)result;
    }

    public static DateTime GetDateTimeForId(long value)
    {
       //strip off the random part - the two lowest bytes
        var timePart = value >> 16;
        var proportionOfTotalPeriod = (decimal) timePart/SEQUENCE_PART_PERMUTATIONS;
        var ticks = (long)(proportionOfTotalPeriod * TotalPeriodTicks);
        var result = PeriodStartDate.AddTicks(ticks);
        return result;
    }
}
0
ajouté