Je ne vois pas vraiment l'intérêt de UUID . Je sais que la probabilité d'une collision est effectivement nulle, mais effectivement nulle n'est même pas presque impossible.
Quelqu'un peut-il donner un exemple où vous n'avez pas d'autre choix que d'utiliser l'UUID? De toutes les utilisations que j'ai vues, je peux voir une conception alternative sans UUID. Certes, la conception peut être un peu plus compliquée, mais au moins elle n’a pas une probabilité d’échec non nulle.
UUID sent les variables globales pour moi. Les variables globales permettent de simplifier la conception de nombreuses façons, mais sa conception est simplement paresseuse.
J'ai écrit le générateur/analyseur UUID pour Ruby, je me considère donc assez bien informé sur le sujet. Il existe quatre versions principales d'UUID:
Les UUID de la version 4 ne sont en réalité que 16 octets d’aléatoire tirés d’un générateur de nombres aléatoires cryptographiquement sécurisé, avec quelques manipulations pour identifier la version et la variante de l’UUID. Il est extrêmement peu probable que ces éléments se rencontrent, mais cela peut arriver si un PRNG est utilisé ou s'il vous arrive d'avoir vraiment, vraiment, vraiment, vraiment pas de chance.
Les UUID des versions 5 et 3 utilisent respectivement les fonctions de hachage SHA1 et MD5 pour combiner un espace de noms avec une partie de données déjà unique afin de générer un UUID. Cela vous permettra, par exemple, de générer un UUID à partir d'une URL. Les collisions ici ne sont possibles que si la fonction de hachage sous-jacente a également une collision.
Les UUID de la version 1 sont les plus courants. Ils utilisent l'adresse MAC de la carte réseau (qui, sauf si elle est usurpée, doit être unique), un horodatage et le bidouillage habituel pour générer l'UUID. Dans le cas d'une machine qui n'a pas d'adresse MAC, les 6 octets de nœud sont générés avec un générateur de nombres aléatoires cryptographiquement sécurisé. Si deux UUID sont générés en séquence suffisamment rapidement pour que l'horodatage corresponde à l'UUID précédent, il est incrémenté de 1. Les collisions ne doivent pas se produire sauf dans les cas suivants: L'adresse MAC est falsifiée; Une machine exécutant deux applications générant un UUID différent produit des UUID exactement au même moment; Deux machines sans carte réseau ou sans accès utilisateur à l'adresse MAC reçoivent la même séquence de nœuds aléatoires et génèrent des UUID exactement au même moment; Nous manquons d'octets pour représenter l'horodatage et revenons à zéro.
En réalité, aucun de ces événements ne se produit par accident dans l'espace ID d'une seule application. À moins d'accepter des identifiants à l'échelle Internet, par exemple, ou dans un environnement non fiable dans lequel des personnes mal intentionnées pourraient faire quelque chose de mal en cas de collision d'identifiants, vous ne devez pas vous inquiéter. Il est essentiel de comprendre que si vous générez le même UUID version 4 que moi, dans la plupart des cas, cela n'a pas d'importance. J'ai généré l'ID dans un espace d'identification complètement différent du vôtre. Mon application ne saura jamais à propos de la collision, donc la collision n'a pas d'importance. Franchement, dans un seul espace applicatif sans acteurs malveillants, l'extinction de toute vie sur Terre se produira bien avant la collision, même avec un UUID version 4, même si vous générez pas mal d'UUID par seconde.
En outre, 2 ^ 64 * 16 correspond à 256 exaoctets. À partir de là, vous auriez besoin de stocker des ID d'une valeur de 256 exaoctets avant d'avoir 50% de chances de collision avec un ID dans un seul espace d'application.
La chose que les UUID vous achètent qui est très difficile à faire autrement est d'obtenir un identifiant unique sans avoir à consulter ou à coordonner avec une autorité centrale . Le problème général de pouvoir obtenir une telle chose sans une sorte d'infrastructure gérée est le problème que résolvent les UUID.
J'ai lu que, selon le paradoxe de l'anniversaire, la probabilité qu'une collision UUID se produise est de 50% une fois que 2 ^ 64 UUID ont été générés. Maintenant, 2 ^ 64 est un assez grand nombre, mais une chance de collision de 50% semble bien trop risquée (par exemple, combien d'UUID doivent exister avant qu'il y ait 5% de chance de collision - même si cela semble trop probable) .
Le problème de cette analyse est double:
Les UUID ne sont pas entièrement aléatoires - il existe des composants principaux de l'UUID basés sur le temps et/ou l'emplacement. Donc, pour avoir une chance réelle de collision, les UUID en collision doivent être générés exactement au même moment à partir de différents générateurs d'UUID. Je dirais que s'il existe une chance raisonnable que plusieurs UUID puissent être générés en même temps, il y a suffisamment de gunk (y compris des informations de localisation ou des bits aléatoires) pour rendre presque impossible la similitude d'une collision entre cet très petit ensemble d'UUID. .
à proprement parler, les UUID doivent uniquement être uniques parmi l'ensemble des autres UUID auxquels ils pourraient être comparés. Si vous générez un UUID à utiliser en tant que clé de base de données, peu importe que ce soit dans un autre univers pervers que le même UUID soit utilisé pour identifier une interface COM. Comme si cela ne causait pas de confusion s'il y avait quelqu'un (ou quelque chose) qui s'appelait "Michael Burr" sur Alpha-Centauri.
Tout a une chance d'échec non nulle. Je me concentrerais sur des problèmes beaucoup plus susceptibles de se produire (c'est-à-dire presque tout ce que vous pouvez penser) que la collision d'UUID
Mettre l'accent sur "raisonnablement" ou, comme vous le dites, "efficacement": le bon fonctionnement du monde réel suffit. La quantité de travail informatique nécessaire pour couvrir cet écart entre "pratiquement unique" et "vraiment unique" est énorme. L'unicité est une courbe avec des rendements décroissants. À un moment donné sur cette courbe, il y a une ligne entre "assez unique" et toujours abordable, et nous courbons TRÈS abruptement. Le coût pour ajouter plus d'unicité devient assez important. L'unicité infinie a un coût infini.
UUID/GUID est, relativement parlant, un moyen simple et rapide de générer un identifiant qui peut être raisonnablement supposé être universellement unique. Ceci est très important dans de nombreux systèmes qui doivent intégrer des données de systèmes auparavant non connectés. Par exemple, si vous avez un système de gestion de contenu qui s'exécute sur deux plates-formes différentes, mais que vous deviez à un moment quelconque importer le contenu d'un système dans un autre. Vous ne voulez pas que les ID changent, vos références entre les données du système A restent donc intactes, mais vous ne voulez pas de conflits avec les données créées dans le système B. Un UUID résout ce problème.
Il n'est jamais absolument nécessaire de créer un UUID. Il est cependant pratique d’avoir une norme où hors connexion les utilisateurs peuvent chacun générer une clé pour quelque chose avec une très faible probabilité de collision.
Cela peut aider à la résolution de la réplication de la base de données, etc.
Il serait facile pour en ligne utilisateurs de générer des clés uniques pour quelque chose sans la surcharge ni la possibilité d’une collision, mais ce n’est pas à cela que servent les UUID.
Quoi qu'il en soit, un mot sur la probabilité de collision, tiré de Wikipedia:
Pour mettre ces chiffres en perspective, le risque annuel d'être touché par une météorite est estimé être une chance sur 17 milliards, équivalent aux chances de créer quelques dizaines de milliards de dollars d’UUID en un an et avoir un duplicata. En d'autres termes, seulement après avoir généré 1 milliard UUIDs toutes les secondes pour les 100 prochaines années, probabilité de création un seul duplicata représenterait environ 50%.
Il existe également une probabilité non nulle que chaque particule de votre corps traverse simultanément le fauteuil sur lequel vous êtes assis et que vous vous retrouviez soudainement assis par terre.
Vous inquiétez-vous à ce sujet?
Un exemple classique est lorsque vous effectuez une réplication entre deux bases de données.
DB (A) insère un enregistrement avec l'ID int 10 et en même temps, DB (B) crée un enregistrement avec l'ID 10. Il s'agit d'une collision.
Avec les UUID, cela ne se produira pas car ils ne correspondront pas. (presque certainement)
J'ai un système pour éviter les UUID. Configurez un serveur quelque part et installez-le de manière à ce que chaque fois qu'un logiciel souhaite obtenir un identificateur unique et universel, il le contacte et le distribue. Simple!
Sauf que cela pose de réels problèmes pratiques, même si nous ignorons totalement la malveillance. En particulier, ce serveur peut échouer ou devenir inaccessible depuis une partie d’Internet. La gestion des pannes de serveur nécessite une réplication, et il est très difficile correct (voir la littérature sur l'algorithme de Paxos pour savoir pourquoi la création d'un consensus est maladroite) et assez lente également. De plus, si tous les serveurs sont inaccessibles depuis une partie particulière du réseau, aucun des clients connectés à ce sous-réseau pourront tout faire car ils attendront tous de nouveaux identifiants.
Alors ... utilisez un algorithme probabiliste simple pour les générer qui ne risquent pas d’échouer pendant le cycle de vie de la Terre, ou (financer et) construire une infrastructure majeure qui va être un PITA de déploiement et avoir des échecs fréquents. Je sais lequel je choisirais.
Si vous ne regardez que les alternatives, par exemple dans le cas d’une application de base de données simple, qui doit interroger la base de données à chaque fois avant de créer un nouvel objet, vous constaterez bientôt qu’utiliser l’UUID peut effectivement réduire la complexité de votre système. Accordé - si vous utilisez les clés int, elles sont en 32 bits, qui seront stockées dans un quart de l’UUID à 128 bits. Accordé - Les algorithmes de génération d'UUID utilisent plus de puissance de calcul que la simple incrémentation d'un nombre. Mais - qui s'en soucie? Les frais généraux liés à la gestion d'une "autorité" permettant d'attribuer des numéros autrement uniques, l'emportent facilement par ordre de grandeur, en fonction de l'espace ID d'unicité souhaité.
Sur UUID == lazy design
Je ne suis pas d'accord pour choisir vos combats. Si un UUID en double est statistiquement impossible et que le calcul est prouvé, pourquoi s'inquiéter? Consacrer du temps à la conception autour de votre petit système de génération N UUID n’est pas pratique, il existe toujours une douzaine d’autres façons d’améliorer votre système.
je ne comprends pas tout le discours sur le risque de collision. Je me fiche de la collision. Je me soucie de la performance cependant.
https://dba.stackexchange.com/a/119129/33649
Les UUID sont un désastre de performances pour les très grandes tables. (200K lignes est Pas "très grand".)
Votre # 3 est vraiment mauvais quand CHARCTER SET est utf8 - CHAR (36) occupe 108 octets!
Les UUID (GUID) sont très "aléatoires". En les utilisant soit comme UNIQUE ou comme La clé PRIMARY sur les grandes tables est très inefficace. C'est à cause de avoir à sauter autour de la table/index chaque fois que vous insérez un nouvel UUID ou SELECT par UUID. Lorsque la table/index est trop volumineux pour tenir dans le cache (voir innodb_buffer_pool_size, qui doit être plus petit que la RAM, généralement 70%), l’UUID «suivant» ne peut pas être mis en cache, donc un disque lent frappé. Quand la table/index est 20 fois plus grande que le cache, seulement 1/20ème (5%) des hits sont mis en cache - vous êtes lié aux E/S.
Donc, n'utilisez pas d'UUID sauf si
vous avez de "petites" tables, ou vous en avez vraiment besoin pour générer identifiants uniques provenant de différents endroits (et n’ayant pas trouvé un autre moyen de le faire). Plus d'informations sur les UUID: http://mysql.rjweb.org/doc.php/uuid (It Comprend des fonctions permettant de convertir des UUID standard à 36 caractères en BINARY (16).)
Avoir un UNIQUE AUTO_INCREMENT et un UNIQUE UUID dans le même la table est un déchet.
Lorsqu’un INSERT se produit, toutes les clés uniques/primaires doivent être vérifiées les doublons. Chaque clé unique suffit pour répondre à l'exigence InnoDB d'avoir une clé primaire. BINARY (16) (16 octets) est un peu volumineux (un argument Contre le PK), mais pas si mal que ça. L'encombrement importe quand vous avez des clés secondaires. InnoDB attaque silencieusement le PK sur la fin de chaque clé secondaire. La principale leçon ici est de minimiser le nombre de clés secondaires, en particulier pour les très grandes les tables. Pour la comparaison: INT UNSIGNED est 4 octets avec une plage de 0..4 milliard. BIGINT est de 8 octets.
Pour ceux qui disent que les UUID sont de mauvaise conception parce qu'ils pourraient (avec une probabilité ridiculement faible), que vos clés générées par DB ne le seront pas ... vous connaissez le risque d'erreur humaine causant une collision sur vos clés générées par DB En raison de certains besoins imprévus, FAR FAR est loin supérieur au risque de collision UUID4. Nous savons que si la base de données est recréée, elle démarrera à nouveau par 1, et combien d’entre nous ont dû recréer une table alors que nous étions certains de ne jamais en avoir besoin? Je mettrais tout mon argent sur la sécurité UUID quand tout commence à mal tourner avec inconnus-inconnus chaque jour.
À l’aide de l’algorithme de la version 1, il semble impossible de se heurter à la contrainte si moins de 10 UUID par milliseconde sont générés à partir de la même adresse MAC
Conceptuellement, l'original (version 1) schéma de génération pour les UUID était de concaténer la version de l'UUID avec le Adresse MAC de l'ordinateur qui est générer l’UUID, et avec le nombre d'intervalles de 100 nanosecondes depuis l'adoption du grégorien calendrier à l'ouest. En pratique, le algorithme réel est plus compliqué . Ce schéma a été critiqué dans qu'il n'est pas suffisamment 'opaque'; il révèle à la fois l'identité du ordinateur qui a généré l’UUID et l'heure à laquelle il l'a fait.
Quelqu'un me corrige si j'ai mal interprété comment cela fonctionne
Outre les cas dans lesquels vous devez utiliser l'API de quelqu'un d'autre qui requiert un UUID, il existe bien entendu toujours une autre solution. Mais ces alternatives vont-elles résoudre tous les problèmes rencontrés par les UUID? Allez-vous finir par ajouter plusieurs couches de hacks, chacun pour résoudre un problème différent, alors que vous auriez pu tous les résoudre en même temps?
Oui, il est théoriquement possible que des identificateurs UUID entrent en collision. Comme d'autres l'ont noté, il est ridiculement improbable au point que cela ne mérite pas d'être considéré. Ce n'est jamais arrivé à ce jour et probablement jamais. Oublie ça.
Le moyen le plus "évident" d'éviter les collisions est de laisser un serveur unique générer des ID uniques sur chaque insertion, ce qui crée évidemment de graves problèmes de performances et ne résout en rien le problème de la génération hors ligne. Oops.
L'autre solution "évidente" est une autorité centrale qui distribue à l'avance des blocs de numéros uniques, qui correspond essentiellement à ce que fait UUID V1 en utilisant l'adresse MAC de la machine génératrice (via IEEE OUI). Toutefois, les adresses MAC en double se produisent parce que toutes les autorités centrales finissent par tout foirer. En pratique, cela est donc beaucoup plus probable qu'une collision UUID V4. Oops.
Le meilleur argument contre l'utilisation des UUID est qu'ils sont "trop gros", mais un schéma (considérablement) plus petit ne réussira inévitablement pas à résoudre les problèmes les plus intéressants; La taille des UUID est un effet secondaire inhérent à leur utilité pour résoudre ces problèmes mêmes.
Il est possible que votre problème ne soit pas assez important pour avoir besoin de ce que les UUID offrent, et dans ce cas, n'hésitez pas à utiliser autre chose. Mais si votre problème s'aggrave de manière inattendue (et la plupart le sont), vous basculerez plus tard - et vous en voudrez pour ne pas les avoir utilisés. Pourquoi concevoir pour l'échec alors qu'il est tout aussi facile de concevoir pour réussir?
Lors de mon dernier emploi, nous obtenions des objets provenant de tiers uniquement identifiés avec UUID. J'ai mis dans une table de recherche UUID-> entier long et utilisé un entier long comme clé primaire parce que c'était beaucoup plus rapide de cette façon.