Image de couverture : UUID v4 vs UUID v7 : la dette technique qui ralentit vos pics d'audience
tech

UUID v4 vs UUID v7 : la dette technique qui ralentit vos pics d'audience

03 June 2026
5 min de lecture
10 vues
Sébastien Muler

UUID v4 vs UUID v7 : la dette technique qui ralentit vos pics d'audience

Il y a trois ans, vous avez choisi uuid_generate_v4() pour vos clés primaires. C'était rapide, simple, et ça marchait. Aujourd'hui, votre application gère des millions de lignes, et vous commencez à voir des signaux inquiétants : latence en hausse, autovacuum qui s'emballe, exports nocturnes de plus en plus longs. Le coupable ? Ce choix technique anodin fait des années plus tôt.

C'est exactement ce que l'équipe derrière ViralVidVault a vécu, comme le raconte Ahmet Gedik sur DEV Community. Leur table de métadonnées vidéo a franchi les 47 millions de lignes, et les UUID v4 sont devenus un goulot d'étranglement critique.

Pourquoi les UUID v4 deviennent un problème à grande échelle

PostgreSQL utilise des index B-tree par défaut. Cette structure adore les insertions séquentielles : une nouvelle clé atterrit sur la page feuille la plus à droite, cette page reste chaude en mémoire (shared_buffers), et vous obtenez des insertions quasi en O(1) avec peu de WAL.

Les UUID v4 font exactement l'inverse. Chaque insertion cible une page différente de l'index, expulse des données utiles du cache, et force une écriture complète de page dans le WAL lors de chaque fenêtre de checkpoint.

Avec une charge de 180 insertions par seconde en pic européen (19h-22h CET), l'équipe a mesuré des effets concrets :

  • 14,2 Go/heure de WAL en pic (majoritairement des full-page writes)
  • Le taux de cache hit sur l'index PK chute de 99,4% à 91,7%
  • La latence d'insertion sur l'index primaire double en six semaines
  • L'export nocturne vers Cloudflare R2 passe de 11 minutes à 38 minutes

Ce n'est pas un problème de volume de requêtes. C'est un problème de structure des identifiants.

UUID v7 : le même format, une logique différente

UUID v7 conserve le format standard sur 128 bits, compatible avec toutes vos colonnes et vos ORM existants. La différence fondamentale est dans sa construction : les 48 premiers bits encodent un timestamp en millisecondes (Unix epoch), suivi de bits de séquence et d'aléatoire.

Résultat : les UUID v7 générés proches dans le temps sont également proches dans l'espace de l'index. On retrouve le comportement séquentiel que PostgreSQL préfère, tout en conservant l'unicité globale et l'absence de coordination entre serveurs.

-- Génération native disponible depuis PostgreSQL 17
SELECT gen_random_uuid(); -- v4, toujours aléatoire

-- Extension uuid-ossp ou fonction personnalisée pour v7 sur PG 16
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid AS $$
DECLARE
  unix_ts_ms BIGINT;
  uuid_bytes BYTEA;
BEGIN
  unix_ts_ms := (EXTRACT(EPOCH FROM CLOCK_TIMESTAMP()) * 1000)::BIGINT;
  uuid_bytes := SET_BYTE(
    SET_BYTE(
      overlay(gen_random_bytes(16) placing
        int8send(unix_ts_ms) from 3 for 6), 6,
        (GET_BYTE(gen_random_bytes(1), 0) & 15) | 112),
    8, (GET_BYTE(gen_random_bytes(1), 0) & 63) | 128);
  RETURN encode(uuid_bytes, 'hex')::uuid;
END;
$$ LANGUAGE plpgsql;

Du côté PHP/Symfony, la bibliothèque symfony/uid supporte nativement les UUID v7 depuis Symfony 6.2 :

use Symfony\Component\Uid\Uuid;

$uuid = Uuid::v7();
// Génère un UUID v7, monotonique et compatible Doctrine

Avec Doctrine ORM, il suffit de déclarer le type uuid sur votre entité — aucun changement de schéma n'est nécessaire si vos colonnes sont déjà de type uuid.

Migrer 47 millions de lignes sans interruption de service

La migration décrite par l'équipe de ViralVidVault est particulièrement instructive, car elle a été réalisée sur un cluster PostgreSQL 16 en production, sans downtime, tout en maintenant la conformité RGPD.

L'approche repose sur plusieurs principes :

1. Double écriture transitoire Ajout d'une colonne id_v7 nullable, alimentée en parallèle par l'application pour toutes les nouvelles insertions. Les anciennes lignes sont backfillées progressivement en heures creuses.

2. Index partiel pendant la transition Création d'un index sur id_v7 uniquement pour les lignes déjà migrées, afin de ne pas pénaliser les performances pendant le processus.

3. Bascule progressive du code applicatif Les lectures et jointures sont migrées feature flag par feature flag, avant de supprimer l'ancienne colonne une fois la migration terminée et validée.

4. Considérations RGPD Les UUID v7 encodent un timestamp. Pour des tables contenant des données personnelles, il convient de documenter ce point dans votre registre de traitements : un UUID v7 peut révéler l'heure approximative de création d'un enregistrement. Ce n'est généralement pas un problème bloquant, mais c'est à évaluer selon votre contexte.

Ce que cela change concrètement

Après migration, les résultats mesurés par l'équipe sont significatifs :

  • WAL en pic redescend autour de 4-5 Go/heure
  • Cache hit ratio sur l'index PK remonte à 99%+
  • La latence d'insertion redevient stable, même en pic européen
  • L'autovacuum reprend un comportement normal

Pour des tables à forte volumétrie et haute fréquence d'insertion, le gain est réel et mesurable dès quelques millions de lignes.

Conclusion : les petits choix ont une longue durée de vie

Le choix entre UUID v4 et UUID v7 peut sembler anodin au démarrage d'un projet. Il ne l'est plus quand votre application passe à l'échelle. La bonne nouvelle : UUID v7 est rétrocompatible au niveau du format, la migration est faisable sans downtime, et l'écosystème PHP/Symfony offre le support nécessaire.

Si vous gérez une table avec des UUID v4 et une croissance soutenue, c'est le moment d'auditer vos métriques d'index et de WAL. La dette technique ne crie pas — elle ralentit silencieusement, jusqu'au pic d'audience qui fait déborder le vase.

Source originale : PostgreSQL UUID v7 Primary Keys for Video Metadata at European Scale par Ahmet Gedik sur DEV Community.

Partager cet article