21 points par GN⁺ 2024-07-06 | 4 commentaires | Partager sur WhatsApp
  • Les UUID sont souvent utilisés comme clés primaires de tables de base de données
    • Ils sont faciles à générer, simples à partager entre systèmes distribués et garantissent l’unicité
    • Vu la taille des UUID, on peut se demander si c’est vraiment le bon choix, mais dans bien des cas, on n’a pas la main sur cette décision
  • Cet article ne cherche pas à répondre à la question « les UUID sont-ils un bon format pour une clé ? », mais explique comment utiliser efficacement des UUID comme clés primaires dans PostgreSQL

Utiliser PostgreSQL et des UUID comme clé primaire

  • Qu’est-ce qu’un UUID ?
    • Les UUID sont souvent utilisés comme clés primaires de tables de base de données
    • Ils peuvent être facilement partagés entre systèmes distribués et garantissent l’unicité
    • Leur taille peut faire douter de leur pertinence, mais on n’a souvent pas d’alternative

Le type de données UUID dans PostgreSQL

  • Stocker un UUID comme chaîne de caractères

    • PostgreSQL fournit le type de données text pour stocker des chaînes
    • Cependant, le type text n’est pas adapté au stockage d’UUID
    • PostgreSQL propose un type dédié, uuid, pour les UUID
    • Le type uuid est un type de données sur 128 bits, qui nécessite 16 octets pour stocker une valeur
    • Le type text ajoute un surcoût de 1 ou 4 octets
  • Résultats de l’expérience

    • Comparaison de deux tables créées pour le test : l’une en type text, l’autre en type uuid
    • Après insertion de 10,000,000 lignes, comparaison de la taille des tables et des index
    • La table utilisant le type text est 54 % plus volumineuse, et la taille de son index est 85 % plus grande

UUID et index B-Tree

  • Index B-Tree et UUID

    • Les UUID aléatoires ne conviennent pas bien aux index B-Tree
    • Les index B-Tree fonctionnent bien avec des valeurs ordonnées
    • En Java, UUID.randomUUID() renvoie un UUID v4, c’est-à-dire une valeur pseudo-aléatoire
    • UUID v7 génère des valeurs ordonnées dans le temps, ce qui le rend adapté aux index B-Tree
  • Utiliser UUID v7

    • Pour utiliser UUID v7 en Java, la bibliothèque java-uuid-generator est nécessaire
    • Générer des UUID v7 peut améliorer les performances d’insertion

Impact d’UUID v7 sur les performances d’INSERT

  • Expérience
    • Création d’une table utilisant UUID v7, puis mesure des performances en insérant 10 fois 10,000 lignes
    • Les résultats restent un peu aléatoires, mais l’insertion d’UUID v7 est environ 2 fois plus rapide

Pour aller plus loin

  • PostgreSQL 17 pourrait prendre en charge UUID v7 nativement
  • Informations sur le format UUID v7
  • Impact des UUID sur les performances lorsqu’ils servent de clé primaire en base de données

Résumé

  • Le problème de la longueur des UUID

    • Même avec des optimisations, les UUID ne sont pas le type le plus optimal pour une clé primaire
    • Si vous avez le choix, envisagez d’autres options comme TSID
  • La nécessité d’optimiser

    • Si vous prévoyez de grands volumes de données ou un trafic élevé, il faut envisager une optimisation
    • Changer une clé primaire est une opération difficile, donc il est important de faire le bon choix dès le départ
  • Remarques

    • L’auteur n’est pas un expert PostgreSQL ; il partage simplement ce qu’il a appris
    • Si cela vous a été utile, n’hésitez pas à faire un retour en commentaire ou sur Twitter

Le récapitulatif de GN⁺

  • Cet article traite des moyens efficaces d’utiliser des UUID comme clés primaires dans PostgreSQL
  • Il montre, expérimentation à l’appui, que l’utilisation d’UUID v7 peut améliorer les performances d’insertion
  • Une optimisation est nécessaire si l’on s’attend à de grands jeux de données ou à un trafic important
  • D’autres options, comme TSID, méritent aussi d’être envisagées

4 commentaires

 
savvykang 2024-07-09

Est-ce déraisonnable d’espérer un encodage en base62 pour les UUID, plutôt que le format standard (hexadécimal + tirets) ?

 
qurare 2024-07-08

uuidv7 est imbattable

uuidv8+ est « divin »

 
bbulbum 2024-07-08

Le plus gros obstacle, c’est que ce n’est pas très convivial pour les humains… J’ai encore besoin de cet aspect dans beaucoup de cas.

 
GN⁺ 2024-07-06
Avis Hacker News
  • Recommande d’utiliser bigserial comme clé primaire compatible B-tree, et d’envisager un UUID encodé en chaîne comme option de localisateur d’enregistrement externe

    • Si des utilisateurs non techniques doivent le citer, envisager d’abord une option simple comme un localisateur de type PNR
    • Ne pas mélanger les types de PK dans le schéma d’un service ou d’une application
    • Lors de l’utilisation de UUIDv7 comme identifiant unique, ne l’utiliser que pour des données où le code temporel intégré a du sens
    • Ne pas utiliser hashids ; cela n’a pas de qualité cryptographique et ce n’est pas familier pour le grand public
    • Lors de l’encodage, ne pas utiliser base64 ni un alphabet contenant des tirets
  • Lors de la conception d’un schéma de base de données, garder à l’esprit les principes de séparation des préoccupations et d’accord mécanique

  • Les ID aléatoires typés de Stripe ne sont en réalité pas aléatoires

    • Ils incluent des métadonnées, des horodatages intégrés, des shards et des clés de référence, ainsi que des informations de version
    • Personnellement, préfère des localisateurs bigserial+HMAC chiffrés en AES et encodés en base58
  • Dans Postgres, les UUID aléatoires ne posent pas de gros problème

    • Les UUID (16 octets) sont plus volumineux que serial (4 octets) ou bigserial (8 octets), mais à l’échelle de l’ensemble d’une table, ce n’est pas un problème majeur
  • Avant d’opposer serial vs. UUID aléatoire vs. UUID ordonné dans Postgres, il y a beaucoup d’autres sujets plus importants à traiter

  • A récemment choisi ULID comme PK Postgres, et cet article a beaucoup aidé : https://brandur.org/nanoglyphs/026-ids

  • Préfère ULID car il est compatible avec le type UUID et intègre un horodatage, ce qui fait qu’un tri par ID revient à un tri chronologique

  • Ce serait bien d’inclure aussi int64 dans la comparaison afin de mesurer le surcoût des UUID par rapport à l’approche traditionnelle

  • Les performances d’insertion sont une mauvaise façon d’évaluer les performances

    • Les performances des B-Tree sont meilleures à l’insertion, mais on peut se demander ce qu’il en est dans le cas de transactions à grande échelle
  • Dans SQLite, UUID4 est préféré car il y a moins de risque de collisions dans le cache de pages pendant les verrous transactionnels

    • Cela pourrait s’appliquer de façon similaire aux systèmes Postgres
  • Préfère les clés primaires entières auto-incrémentées

    • C’est facile à comprendre et simple à trier
    • Dans les gros projets de batch, on peut stocker la dernière clé primaire et récupérer tout ce qui est supérieur
  • Le benchmark du temps d’insertion de UUIDv7 inclut le temps de génération du UUID

    • Aimerait simplement voir isolé le coût de mise à jour de l’index
  • Il est peu probable que PostgreSQL 17 inclue la prise en charge de UUIDv7

    • Le committer a récemment été retiré du travail en cours, et la version 17 est déjà en gel fonctionnel
  • A commencé à utiliser python-ulid, et estime que ULID est supérieur à UUID

  • Le lien vers la norme UUID v7 est obsolète ; se référer plutôt à la RFC 9562 : https://datatracker.ietf.org/doc/html/rfc9562