UUID v7 Generator
Generate time-ordered UUID v7 for database primary keys
…
Formatera
Vad är UUID v7?
UUID v7 är ett nästa generations UUID-format standardiserat i RFC 9562 (maj 2024). Det kodar en 48-bitars Unix-millisekundtidsstämpel i de mest signifikanta bitarna, följt av versions- och variantmarkörer, och fyller de återstående bitarna med kryptografiskt säkra slumpmässiga data.
Eftersom tidsstämpeln upptar de höga bitarna sorteras UUID v7-värden kronologiskt — både lexikografiskt och numeriskt. Det gör dem till ett utmärkt val för databasprimärnycklar, där slumpmässiga UUID:n (v4) orsakar B-tree-indexfragmentering.
Varför slumpmässiga UUID:n fragmenterar databasindex
B-tree-index — som används av PostgreSQL, MySQL, SQLite och de flesta andra databaser — håller rader sorterade efter nyckelvärde. När du infogar en ny rad måste databasen placera den på rätt sorterad position i indexet.
Med UUID v4 (helt slumpmässigt) landar varje ny infogning på en i princip slumpmässig position i indexträdet. Det tvingar databasen att konstant läsa och skriva om interna indexsidor, dela upp fulla sidor och lämna andra halvtomma. Resultatet är ett fragmenterat, uppblåst index som bromsar både skrivningar och läsningar när tabellen växer.
UUID v7 bitlayout
UUID v7 är 128 bitar brett, uppdelat i sex fält:
| Bitar | Fält | Syfte |
|---|---|---|
| 48 | unix_ts_ms | 48-bitars Unix-tidsstämpel i millisekunder — upptar hela den höga hälften |
| 4 | ver | Versionsnummer — alltid 0111 (decimalt 7) |
| 12 | rand_a | 12 bitar kryptografiskt säkra slumpmässiga data |
| 2 | var | Variantmarkör — alltid 10 (RFC 4122-variant) |
| 62 | rand_b | 62 bitar kryptografiskt säkra slumpmässiga data |
Tidsstämpelprecisionen är 1 millisekund. Inom samma millisekund ordnas UUID v7-värden av deras slumpmässiga suffix — de garanteras inte vara monotont ökande sub-millisekund, men de är k-sorterbara: ID:n som genereras nära varandra i tid sorteras nära varandra i indexet.
UUID v7 vs UUID v1
Både UUID v1 och UUID v7 innehåller en tidsstämpel, men de skiljer sig avsevärt i design:
| Funktion | UUID v7 | UUID v1 |
|---|---|---|
| Epok / Tidsbas | Unix-epok (1 jan 1970) | Gregoriansk epok (15 okt 1582) |
| Tidsprecision | 1 millisekund | 100 nanosekunder |
| Sorterbar | Ja — k-sorterbar by design | Nej — tidsfält är blandade i UUID-layouten |
| Integritet | Ingen värdinformation läckt | Inbäddar MAC-adress från genererande värd |
| DB-indexprestanda | Utmärkt — sekventiella infogningar, minimal fragmentering | Dålig — icke-sekventiell trots tidsstämpel |
| Standard | RFC 9562 (2024) | RFC 4122 (2005) |
| Inbyggt webbläsarstöd | Ännu inte (inget crypto.randomUUID v7) | Inte tillgängligt inbyggt |
För alla nya projekt som behöver tidsordnade UUID:n, föredra UUID v7 framför UUID v1. UUID v1 är ett äldre format och läcker värdinformation.
UUID v7 vs ULID
ULID (Universally Unique Lexicographically Sortable Identifier) löser ett liknande problem som UUID v7. Här är en jämförelse:
- Följer RFC 9562 UUID-standarden — kompatibel med all UUID-tooling
- Bindestreck-hexformat — universellt erkänt
- Inbyggt databasstöd för UUID-kolumner
- 128 bitar totalt
- Crockford Base32-kodning — 26 tecken, något mer kompakt
- Skiftlägeskänsligt och undviker tvetydiga tecken (I, L, O, U)
- Mer mänskligt läsbar vid en snabb blick
- Kräver ett bibliotek — inget inbyggt plattformsstöd
Om du redan befinner dig i ett UUID-ekosystem (PostgreSQL uuid-kolumn, REST-API:er som returnerar UUID:n), använd UUID v7. Om du börjar från scratch och föredrar en mer användarvänlig kodning, är ULID ett rimligt alternativ.
Använda UUID v7 i databaser
UUID v7 genereras ännu inte inbyggt av de flesta databaser, men kan lagras i standard UUID-kolumner och genereras i applikationskod eller via tillägg:
uuid-kolumn. Tillägget pg-uuidv7 lägger till en uuid_generate_v7() serversidsfunktion om du behöver DB-genererade ID:n.BINARY(16) eller CHAR(36)-kolumn. Generera i applikationskod. MySQL 8.0+ har ordnat UUID-stöd via UUID_TO_BIN(UUID(), 1) för v1, men v7 kräver generering på applikationsnivå.TEXT (36 tecken) eller BLOB (16 byte). Generera i applikationskod. Lexikografisk sortering på TEXT fungerar korrekt eftersom UUID v7 använder ett tidsstämpelprefix med fast bredd.Kodexempel
UUID v7 är ännu inte tillgängligt via crypto.randomUUID(). Använd ett bibliotek som uuidv7 (npm) tills inbyggt stöd anländer:
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# 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 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()
);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"