UUID v7 Generator
Menghasilkan UUID v7 berurutan waktu untuk kunci utama basis data
…
Format
Apa itu UUID v7?
UUID v7 adalah format UUID generasi berikutnya yang distandarisasi dalam RFC 9562 (Mei 2024). UUID v7 mengkodekan timestamp Unix 48-bit dalam bit paling signifikan, diikuti oleh penanda versi dan varian, dan mengisi bit yang tersisa dengan data acak yang aman secara kriptografi.
Karena timestamp menempati bit tinggi, nilai UUID v7 diurutkan secara kronologis. Ini menjadikannya pilihan yang sangat baik untuk kunci primer database, di mana UUID acak (v4) menyebabkan fragmentasi indeks B-tree.
Mengapa UUID Acak Memfragmentasi Indeks Database
Indeks B-tree — digunakan oleh PostgreSQL, MySQL, SQLite, dan sebagian besar database lainnya — menyimpan baris diurutkan berdasarkan nilai kunci.
Dengan UUID v4 (sepenuhnya acak), setiap penyisipan baru mendarat di posisi yang pada dasarnya acak dalam pohon indeks. Ini memaksa database untuk terus membaca dan menulis ulang halaman indeks internal.
Tata Letak Bit UUID v7
UUID v7 selebar 128 bit, dibagi menjadi enam field:
| Bit | Field | Tujuan |
|---|---|---|
| 48 | unix_ts_ms | Timestamp Unix 48-bit dalam milidetik — menempati seluruh paruh tinggi |
| 4 | ver | Nomor versi — selalu 0111 (desimal 7) |
| 12 | rand_a | 12 bit data acak yang aman secara kriptografi |
| 2 | var | Penanda varian — selalu 10 (varian RFC 4122) |
| 62 | rand_b | 62 bit data acak yang aman secara kriptografi |
Presisi timestamp adalah 1 milidetik. Dalam milidetik yang sama, nilai UUID v7 diurutkan berdasarkan sufiks acak mereka.
UUID v7 vs UUID v1
UUID v1 dan UUID v7 keduanya menyematkan timestamp, tetapi berbeda secara signifikan dalam desain:
| Fitur | UUID v7 | UUID v1 |
|---|---|---|
| Epoch / Basis Waktu | Epoch Unix (1 Jan 1970) | Epoch Gregorian (15 Okt 1582) |
| Presisi Waktu | 1 milidetik | 100 nanodetik |
| Dapat Diurutkan | Ya — k-sortable berdasarkan desain | Tidak — field waktu tersebar dalam tata letak UUID |
| Privasi | Tidak ada informasi host yang bocor | Menyematkan alamat MAC host yang menghasilkan |
| Performa Indeks DB | Sangat baik — penyisipan berurutan, fragmentasi minimal | Buruk — tidak berurutan meskipun ada timestamp |
| Standar | RFC 9562 (2024) | RFC 4122 (2005) |
| Dukungan Browser Native | Belum (tidak ada crypto.randomUUID v7) | Tidak tersedia secara native |
Untuk proyek baru yang membutuhkan UUID berurutan waktu, lebih pilih UUID v7 daripada UUID v1.
UUID v7 vs ULID
ULID (Universally Unique Lexicographically Sortable Identifier) memecahkan masalah serupa dengan UUID v7:
- Mengikuti standar UUID RFC 9562 — kompatibel dengan semua alat UUID
- Format hex bertanda hubung — dikenali secara universal
- Dukungan kolom UUID database native
- 128 bit total
- Pengkodean Crockford Base32 — 26 karakter, sedikit lebih kompak
- Tidak peka huruf besar/kecil dan menghindari karakter ambigu (I, L, O, U)
- Lebih mudah dibaca manusia sekilas
- Memerlukan library — tidak ada dukungan platform native
Jika Anda sudah dalam ekosistem UUID (kolom uuid PostgreSQL, REST API yang mengembalikan UUID), gunakan UUID v7. Jika memulai dari awal dan lebih suka pengkodean ramah manusia, ULID adalah alternatif yang baik.
Menggunakan UUID v7 di Database
UUID v7 belum dihasilkan secara native oleh sebagian besar database, tetapi dapat disimpan di kolom UUID standar:
uuid. Ekstensi pg-uuidv7 menambahkan fungsi sisi server uuid_generate_v7().BINARY(16) atau CHAR(36). Buat di kode aplikasi.TEXT (36 karakter) atau BLOB (16 byte). Buat di kode aplikasi.Contoh Kode
UUID v7 belum tersedia melalui crypto.randomUUID(). Gunakan library seperti uuidv7 (npm) hingga dukungan native tiba:
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"