veilletech.fr
23 oct. Feed du jour
#08 POSTGRES Article

UUIDv7 : ni ordre strict, ni date fiable

Un identifiant n'est pas une horloge.

Un billet d'alexsci.com montre qu'UUIDv7 ne garantit ni croissance stricte, ni date de création fiable, ni valeurs impossibles à deviner : seule l'unicité est assurée. Avec le générateur de Python 3.14, un recul d'horloge d'une heure fait grossir l'écart sans fin sous charge. La date intégrée peut aussi trahir la création d'un compte.

3 min de lectureintermédiairevidéo 1:18
Partager
Sommaire6 sections
  1. Ce qui se passe
  2. La date n'est pas toujours la date
  3. L'ordre n'est pas strict
  4. Une date qui fuit
  5. Comment s'y prendre
  6. À retenir

Ce qui se passe

Les articles sur UUIDv7 en vantent trois avantages : des identifiants croissants, une date de création intégrée, des valeurs imprévisibles. L'auteur du blog alexsci.com a relu la RFC 9562 et plusieurs implémentations : aucune de ces propriétés n'est tenue strictement. La seule garantie solide est l'unicité, donc la résistance aux collisions. Il renvoie à un autre billet pour le caractère devinable des identifiants. Ce texte est une analyse, pas une alerte : il ne demande pas d'abandonner UUIDv7.

La date n'est pas toujours la date

La RFC 9562 (§6.1) autorise les implémentations à modifier le champ horodatage et n'exige aucune proximité avec l'heure réelle ; le §6.2 les laisse l'avancer au-delà de l'horloge pour rester monotones. La documentation de Postgres le dit aussi pour uuid_extract_timestamp : la date extraite n'est pas forcément celle de la génération.

Démonstration sur uuid.uuid7() de Python 3.14 : si l'horloge recule d'une heure et que la charge dépasse un identifiant par milliseconde, l'écart entre l'horodatage et l'heure réelle ne se résorbe pas, il augmente. Version condensée du billet, non rejouée ici :

Python
import uuid
from datetime import datetime

def ecart():
    ms = uuid.uuid7().time               # horodatage intégré, en millisecondes
    return ms / 1000 - datetime.now().timestamp()

print(ecart())
input("Reculez l'horloge d'une heure, puis Entrée")
while True:
    for _ in range(100_000):
        uuid.uuid7()
    print(ecart())

Le billet relève 3 695 s, puis 3 795, 3 894 et 3 994 s : environ 100 s de plus à chaque série. Les développeurs de CPython jugent ce comportement conforme à la RFC (issue python/cpython#138862).

L'ordre n'est pas strict

Une date qui fuit

L'horodatage fait partie de l'identifiant : on ne peut pas partager l'un sans l'autre. Une URL de profil dont l'identifiant est un UUIDv7 révèle le moment précis de création du compte. L'auteur reconnaît que c'est rarement un enjeu majeur, mais qu'il compte dans certains contextes.

Comment s'y prendre

  1. Ne pas lire l'horodatage d'un UUIDv7 comme date de création : garder une colonne created_at.
  2. Ne pas bâtir un curseur de pagination qui suppose un ordre strict.
  3. Avant de choisir une bibliothèque, lui poser les questions du billet : est-elle conforme à la RFC ? quelles propriétés garantit-elle, et sous quelles limites ? dans quels cas modifie-t-elle l'horodatage ? quelle horloge suppose-t-elle ?
  4. Un ordre approximatif reste utile pour l'index : l'auteur ne conseille pas de remplacer UUIDv7 partout.

Source : alexsci.com, billet sans date affichée, relayé par Lobste.rs le 23 octobre 2026. Source en anglais.