web-dev-qa-db-fra.com

Performances UUID dans MySQL?

Nous envisageons d'utiliser les valeurs UUID comme clés primaires pour notre base de données MySQL. Les données insérées sont générées à partir de dizaines, de centaines, voire de milliers d'ordinateurs distants. Elles sont insérées à un taux de 100 à 40 000 insertions par seconde. Nous ne ferons jamais aucune mise à jour.

La base de données elle-même atteindra environ 50 millions d'enregistrements avant que nous commencions à supprimer les données, donc pas une base de données volumineuse, mais pas infime non plus. Nous prévoyons également de faire appel à InnoDB, même si nous sommes disposés à le changer s’il existe un meilleur moteur pour ce que nous faisons.

Nous étions prêts à utiliser l'UUID de type 4 de Java, mais certains tests ont révélé un comportement étrange. D'une part, nous stockons varchar (36) et je réalise maintenant que nous ferions mieux d'utiliser binaire (16) - bien que je ne sois pas encore mieux.

La grande question est la suivante: dans quelle mesure ces données aléatoires gâchent-elles l’index lorsque nous avons 50 millions d’enregistrements? Serions-nous mieux si nous utilisions, par exemple, un UUID de type 1 dans lequel les bits les plus à gauche étaient horodatés? Ou peut-être devrions-nous abandonner entièrement les UUID et envisager l'auto-incrémentation de clés primaires?

Je recherche des idées/conseils généraux sur les performances de différents types d'UUID lorsqu'ils sont stockés sous la forme d'une clé d'index/primaire dans MySQL. Merci!

70

Un UUID est un ID universellement unique. C'est la partie universelle que vous devriez considérer ici.

Avez-vous vraiment besoin que les identifiants soient universellement uniques? Si tel est le cas, alors les UUID peuvent être votre seul choix.

Je suggérerais fortement que si vous do utilisez des UUID, vous les stockiez sous forme de nombre et non de chaîne. Si vous avez plus de 50 millions d'enregistrements, les économies d'espace de stockage amélioreront vos performances (bien que je ne puisse pas dire de combien).

Si vos identifiants n'ont pas besoin d'être universellement uniques, je ne pense pas que vous puissiez faire mieux que d'utiliser simplement auto_increment, ce qui garantit que les identifiants seront uniques dans une table (puisque la valeur sera incrémentée à chaque fois)

29
Dancrumb

À mon travail, nous utilisons UUID en tant que PC. Ce que je peux vous dire par expérience, c’est de ne pas les utiliser en tant que PK (SQL Server en passant).

C’est l’une des choses que lorsque vous avez moins de 1000 enregistrements, c’est correct, mais lorsque vous en avez des millions, c’est la pire chose à faire. Pourquoi? Etant donné que les UUID ne sont pas séquentiels, chaque fois qu'un nouvel enregistrement est inséré, MSSQL doit consulter la page appropriée pour insérer l'enregistrement, puis l'insérer. La conséquence vraiment laide avec ceci est que les pages se retrouvent toutes dans des tailles différentes et qu'elles se retrouvent fragmentées. Nous devons maintenant effectuer une défragmentation périodique.

Quand vous utilisez un auto-incrémentation, MSSQL va toujours à la dernière page et vous vous retrouvez avec des pages de tailles égales (en théorie) donc la performance pour sélectionner ces enregistrements est bien meilleure (aussi parce que les INSERT ne bloquent pas la table/page Si longtemps).

Cependant, le gros avantage de l’utilisation de l’UUID en tant que PC est que si nous avons des grappes de bases de données, il n’y aura pas de conflit lors de la fusion.

Je recommanderais le modèle suivant: 1. Identité PK INT 2. Colonne supplémentaire générée automatiquement en tant qu’UUID.

De cette façon, le processus de fusion est possible (UUID serait votre clé REAL, tandis que la PK ne serait qu'un élément temporaire qui vous donnerait de bonnes performances).

REMARQUE: La meilleure solution consiste à utiliser NEWSEQUENTIALID (comme je le disais dans les commentaires), mais pour une application héritée avec peu de temps pour le refactorisation (et pire encore, ne pas contrôler tous les inserts), il est impossible de le faire ..__ Mais en effet, à partir de 2017, je dirais que la meilleure solution est NEWSEQUENTIALID ou Guid.Comb avec NHibernate.

J'espère que cela t'aides

66
Kat Lim Ruiz

Il convient de noter que les auto-incréments sont générés un par un et qu’ils ne peuvent pas être résolus par une solution parallèle. La lutte pour l’utilisation des UUID dépend finalement de ce que vous voulez réaliser par rapport à ce que vous sacrifiez potentiellement.

Sur la performance, brièvement :

Un UUID comme celui ci-dessus est 36 caractères longs, y compris les tirets. Si vous stockez ce VARCHAR (36), vous êtes va diminuer les performances de comparaison de façon spectaculaire. Ceci est votre primaire clé, vous ne voulez pas que ce soit lent.

À son niveau de bits, un UUID est de 128 bits, ce qui signifie qu'il tiendra dans 16 octets, notez que ce n’est pas très lisible, mais il gardera le stockage bas, et est seulement 4 fois plus grand qu'un int 32 bits, ou 2 fois plus grand qu'un int de 64 bits. Je vais utiliser un VARBINARY (16) Théoriquement, cela peut fonctionner sans un beaucoup de frais généraux.

Je recommande de lire les deux posts suivants:

Je compte entre les deux, ils répondent à votre question.

25
Kyle Rozendo

J'ai tendance à éviter les UUID simplement parce que c'est une douleur à stocker et à utiliser comme clé primaire, mais il y a des avantages. Le principal est qu'ils sont uniques. 

J'ai l'habitude de résoudre le problème et d'éviter UUID en utilisant des champs à double clé.

COLLECTEUR = UNIQUE ASSIGNÉ À UNE MACHINE

ID = RECORD COLLECTED PAR LE COLLECTEUR (champ auto_inc)

Cela m'offre deux choses. Vitesse des champs à incrustation automatique et unicité des données stockées dans un emplacement central après leur collecte et leur regroupement. Je sais aussi, en parcourant les données, où elles ont été collectées, ce qui est souvent très important pour mes besoins.

J'ai vu de nombreux cas concernant d'autres ensembles de données pour des clients pour lesquels ils ont décidé d'utiliser l'UUID tout en disposant d'un champ dans lequel les données ont été collectées, ce qui est vraiment une perte de temps. Il suffit d’utiliser deux champs (ou plus si nécessaire) car votre clé est vraiment utile.

Je viens de voir trop d'accidents de performance en utilisant UUID. Ils se sentent comme une triche ...

5
Glenn J. Schworak

Au lieu de générer de manière centralisée des clés uniques pour chaque insertion, pourquoi ne pas allouer des blocs de clés à des serveurs individuels? Lorsqu'ils n'ont plus de clé, ils peuvent demander un nouveau bloc. Ensuite, vous résolvez le problème des frais généraux en vous connectant pour chaque insertion.

Keyserver conserve le prochain identifiant disponible

  • Le serveur 1 demande un bloc d'identification.
  • Retour du serveur de clés (1 000)
    Le serveur 1 peut insérer 1000 enregistrements jusqu'à ce qu'il ait besoin de demander un nouveau bloc
  • Le serveur 2 demande un bloc d'index.
  • Retour du serveur de clés (1001,2000)
  • etc...

Vous pouvez proposer une version plus sophistiquée dans laquelle un serveur peut demander le nombre de clés nécessaires ou renvoyer des blocs inutilisés au serveur de clés, lequel devra alors bien sûr conserver une carte des blocs utilisés/inutilisés.

3
Bouke Versteegh

J'attribuerais à chaque serveur un identifiant numérique de manière transactionnelle . Ensuite, chaque enregistrement inséré créera simplement un auto-incrémentation de son propre compteur. sélectionnez performance Basé sur ServerID (si nécessaire) peut être beaucoup mieux.

2
Nikolai

Qu'en est-il des UID fabriqués à la main? Attribuez un ID à chacun des milliers de serveurs et faites de la clé primaire une clé combinée auto-incrémentée, MachineID ???

1
MindStalker

Comme la clé primaire est générée de manière décentralisée, vous n’avez de toute façon pas la possibilité d’utiliser un auto_increment.

Si vous ne devez pas masquer l'identité des ordinateurs distants, utilisez des UUID de type 1 au lieu d'UUID. Ils sont plus faciles à générer et peuvent au moins ne pas nuire aux performances de la base de données.

Il en va de même pour varchar (char, vraiment) et binaire: cela ne peut que faire avancer les choses. Est-il vraiment important d'améliorer les performances?

1
user3850

La réponse courte est que de nombreuses bases de données ont des problèmes de performances (en particulier avec des volumes INSERT élevés) en raison d'un conflit entre leur méthode d'indexation et l'entropie délibérée des UUID dans les bits de poids fort. Il y a plusieurs hacks communs:

  • choisissez un type d'index différent (par exemple, non clusterisé sur MSSQL), cela ne vous dérange pas
  • transmettre les données pour déplacer l’entropie vers des bits de poids faible (par exemple, réordonner les octets d’UUID V1 sur MySQL)
  • faire de l'UUID une clé secondaire avec une clé primaire auto-incrémentée

... Mais ce sont tous des bidouilles - et probablement des fragiles à cela.

La meilleure solution, mais malheureusement la plus lente, consiste à demander à votre fournisseur d'améliorer son produit afin qu'il puisse traiter les UUID comme des clés primaires, comme tout autre type. Ils ne devraient pas vous obliger à utiliser vos propres moyens pour compenser leur incapacité à résoudre ce qui est devenu un cas d'utilisation courant et ne fera que grandir.

0
StephenS