Generatore UUID v7

Genera UUID v7 ordinati nel tempo per chiavi primarie di database

Formatta

Quantità:

Cos'è UUID v7?

UUID v7 è un formato UUID di nuova generazione standardizzato in RFC 9562 (maggio 2024). Codifica un timestamp Unix a 48 bit in millisecondi nei bit più significativi, seguito da marcatori di versione e variante, e riempie i bit rimanenti con dati casuali crittograficamente sicuri.

Poiché il timestamp occupa i bit più significativi, i valori UUID v7 si ordinano cronologicamente — sia lessicograficamente che numericamente. Questo li rende un'ottima scelta per le chiavi primarie dei database, dove gli UUID casuali (v4) causano frammentazione degli indici B-tree.

Perché gli UUID casuali frammentano gli indici dei database

Gli indici B-tree — usati da PostgreSQL, MySQL, SQLite e dalla maggior parte degli altri database — mantengono le righe ordinate per valore di chiave. Quando si inserisce una nuova riga, il database deve posizionarla nella posizione ordinata corretta all'interno dell'albero degli indici.

Con UUID v4 (completamente casuale), ogni nuovo inserimento attertra in una posizione essenzialmente casuale nell'albero degli indici. Questo costringe il database a leggere e riscrivere costantemente le pagine degli indici interni, dividendo le pagine piene e lasciandone altre a metà vuote. Il risultato è un indice frammentato e gonfio che rallenta sia le scritture che le letture man mano che la tabella cresce.

Layout dei bit di UUID v7

UUID v7 è largo 128 bit, diviso in sei campi:

BitCampoScopo
48unix_ts_msTimestamp Unix a 48 bit in millisecondi — occupa l'intera metà superiore
4verNumero di versione — sempre 0111 (decimale 7)
12rand_a12 bit di dati casuali crittograficamente sicuri
2varMarcatore di variante — sempre 10 (variante RFC 4122)
62rand_b62 bit di dati casuali crittograficamente sicuri

La precisione del timestamp è 1 millisecondo. All'interno dello stesso millisecondo, i valori UUID v7 sono ordinati dal loro suffisso casuale — non è garantito che siano monotonicamente crescenti sotto il millisecondo, ma sono k-sortable: gli ID generati vicini nel tempo si ordineranno vicini nell'indice.

UUID v7 vs UUID v1

Sia UUID v1 che UUID v7 incorporano un timestamp, ma differiscono significativamente nel design:

FunzionalitàUUID v7UUID v1
Epoch / Base temporaleEpoch Unix (1 gen. 1970)Epoch gregoriano (15 ott. 1582)
Precisione temporale1 millisecondo100 nanosecondi
OrdinabileSì — k-sortable per designNo — i campi temporali sono mescolati nel layout UUID
PrivacyNessuna informazione sull'host divulgataIncorpora l'indirizzo MAC dell'host generatore
Prestazioni indice DBEccellenti — inserimenti sequenziali, frammentazione minimaScarse — non sequenziale nonostante il timestamp
StandardRFC 9562 (2024)RFC 4122 (2005)
Supporto nativo browserNon ancora (nessun crypto.randomUUID v7)Non disponibile nativamente

Per qualsiasi nuovo progetto che necessita di UUID ordinati nel tempo, preferire UUID v7 a UUID v1. UUID v1 è legacy e divulga informazioni sull'host.

UUID v7 vs ULID

ULID (Universally Unique Lexicographically Sortable Identifier) risolve un problema simile a UUID v7. Ecco come si confrontano:

UUID v7
  • Segue lo standard UUID RFC 9562 — compatibile con tutti gli strumenti UUID
  • Formato esadecimale con trattini — universalmente riconosciuto
  • Supporto nativo per colonne UUID nei database
  • 128 bit totali
ULID
  • Codifica Crockford Base32 — 26 caratteri, leggermente più compatto
  • Case-insensitive ed evita caratteri ambigui (I, L, O, U)
  • Più leggibile dall'uomo a colpo d'occhio
  • Richiede una libreria — nessun supporto nativo della piattaforma

Se si è già in un ecosistema UUID (colonna uuid PostgreSQL, API REST che restituiscono UUID), usare UUID v7. Se si parte da zero e si preferisce una codifica più user-friendly, ULID è un'alternativa ragionevole.

Usare UUID v7 nei database

UUID v7 non è ancora generato nativamente dalla maggior parte dei database, ma può essere memorizzato in colonne UUID standard e generato nel codice applicativo o tramite estensioni:

PostgreSQL
PostgreSQL: memorizzare in una colonna uuid. L'estensione pg-uuidv7 aggiunge una funzione lato server uuid_generate_v7() se si hanno bisogno di ID generati dal DB.
MySQL / MariaDB
MySQL / MariaDB: memorizzare in una colonna BINARY(16) o CHAR(36). Generare nel codice applicativo. MySQL 8.0+ ha supporto UUID ordinato tramite UUID_TO_BIN(UUID(), 1) per v1, ma v7 richiede generazione a livello applicativo.
SQLite
SQLite: memorizzare come TEXT (36 chars) o BLOB (16 byte). Generare nel codice applicativo. L'ordinamento lessicografico su TEXT funziona correttamente perché UUID v7 usa un prefisso timestamp a larghezza fissa.

Esempi di codice

UUID v7 non è ancora disponibile tramite crypto.randomUUID(). Usare una libreria come uuidv7 (npm) finché non arriva il supporto nativo:

JavaScript (browser / Node.js 20+)
function generateUuidV7() {
  const buf = new Uint8Array(16)
  crypto.getRandomValues(buf)

  const ms = BigInt(Date.now())

  // Embed 48-bit Unix ms timestamp
  buf[0] = Number((ms >> 40n) & 0xFFn)
  buf[1] = Number((ms >> 32n) & 0xFFn)
  buf[2] = Number((ms >> 24n) & 0xFFn)
  buf[3] = Number((ms >> 16n) & 0xFFn)
  buf[4] = Number((ms >> 8n)  & 0xFFn)
  buf[5] = Number(ms & 0xFFn)

  // Set version 7 (0111xxxx)
  buf[6] = (buf[6] & 0x0F) | 0x70

  // Set variant (10xxxxxx)
  buf[8] = (buf[8] & 0x3F) | 0x80

  const hex = [...buf].map(b => b.toString(16).padStart(2, '0')).join('')
  return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`
}

// Node.js 20+ built-in
// import { randomUUID } from 'node:crypto'  // v4 only — no v7 yet in stdlib
Python (uuid7 library)
# pip install uuid7
import uuid_extensions

uid = uuid_extensions.uuid7()
print(uid)                       # e.g. 018e2b3d-1a2b-7000-8000-abc123456789
print(uid.time)                  # Unix ms timestamp embedded in the UUID

# Or as a plain string
from uuid_extensions import uuid7str
print(uuid7str())
PostgreSQL — generate UUID v7
-- PostgreSQL 13+ extension-free implementation
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid
LANGUAGE sql
AS $$
  SELECT encode(
    set_bit(
      set_bit(
        overlay(
          uuid_send(gen_random_uuid())
          PLACING substring(int8send(floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint) FROM 3)
          FROM 1 FOR 6
        ),
        52, 1
      ),
      53, 1
    ),
    'hex'
  )::uuid;
$$;

-- Usage as a default primary key
CREATE TABLE events (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
  payload jsonb,
  created_at timestamptz DEFAULT now()
);
TypeScript — extract timestamp from UUID v7
function extractTimestamp(uuid: string): Date {
  const hex = uuid.replace(/-/g, '')
  const ms = parseInt(hex.slice(0, 12), 16)  // first 48 bits = ms timestamp
  return new Date(ms)
}

const uid = '018e2b3d-1a2b-7000-8000-abc123456789'
console.log(extractTimestamp(uid).toISOString())
// → "2024-03-15T10:22:05.259Z"

Domande Frequenti

UUID v7 è retrocompatibile con UUID v4?
Sì. UUID v7 usa lo stesso formato wire a 128 bit, 32 cifre esadecimali, con trattini di tutte le altre versioni UUID. Qualsiasi sistema che memorizza o trasmette UUID accetterà un UUID v7 senza modifiche. Il nibble di versione (7) e i bit di variante lo identificano come v7 per gli strumenti che ispezionano la struttura UUID.
UUID v7 espone il timestamp di generazione?
Sì — i primi 48 bit sono un timestamp Unix in millisecondi, quindi chiunque abbia l'UUID può determinare approssimativamente quando è stato generato (al millisecondo più vicino). Se esporre il tempo di creazione è una preoccupazione per il caso d'uso, usare invece UUID v4.
Posso usare UUID v7 come chiave primaria del database senza una colonna created_at separata?
Sì. Poiché UUID v7 incorpora un timestamp di precisione millisecondo, è possibile decodificare quel valore per ottenere il tempo di creazione approssimativo. Tuttavia, per chiarezza e indicizzabilità, molti team mantengono comunque una colonna created_at esplicita e usano UUID v7 solo per la colonna ID.
Quanta entropia ha UUID v7?
UUID v7 ha 74 bit di dati casuali (12 bit in rand_a + 62 bit in rand_b). Questo è leggermente inferiore ai 122 bit di UUID v4 ma fornisce comunque uno spazio senza collisioni astronomicamente grande per uso pratico. La ridotta casualità è il compromesso per guadagnare l'ordinabilità per timestamp.
UUID v7 è supportato nativamente nei browser o Node.js?
Non ancora all'inizio del 2025. Lo standard RFC 9562 è stato pubblicato a maggio 2024 e il supporto della piattaforma sta ancora recuperando. Usare il pacchetto npm uuidv7 per ora. Il supporto nativo tramite crypto.randomUUID({ version: 7 }) o API simili potrebbe arrivare nelle future versioni di browser e Node.js.