Skip to content

UUIDv7 Bagus untuk Primary Key, Buruk sebagai Jam: 4 Tes Sebelum Migrasi

Terbit Terakhir diperbarui 5 menit baca

Poin penting

  • UUIDv7 menaruh timestamp milidetik di bit tinggi, sehingga ID baru mendarat di dekat ujung indeks B-tree, bukan di halaman acak seperti UUIDv4.
  • RFC 9562 mengizinkan implementasi mengubah timestamp dan tidak menjamin seberapa dekat nilainya dengan waktu nyata.
  • Pada tes yang dikutip, menggeser jam sistem mundur satu jam membuat timestamp uuid7() Python berjalan sekitar satu jam di depan waktu nyata, dan selisihnya terus membesar.
  • UUIDv7 punya paling banyak 74 bit acak, dan di Python sebagian darinya adalah counter, jadi jangan pernah dipakai sebagai reset token, session ID, atau link yang tidak bisa ditebak.
  • Aturan praktis: UUIDv7 untuk primary key, kolom created_at untuk waktu, dan token acak untuk apa pun yang memberi akses.

Versi bahasa Inggris: UUIDv7 Is a Great Database Key and a Bad Clock: 4 Tests Before You Migrate.

UUIDv7 menyelesaikan masalah database yang nyata. Ia juga diam-diam mengundang asumsi yang buruk: bahwa ID memberi tahu waktu, dan bahwa waktu itu aman ditampilkan ke dunia.

Sebuah tulisan dari 19 Oktober 2026, “UUIDv7 doesn’t have the properties you think it does”, membongkar asumsi itu dengan tes yang bisa Anda reproduksi. Saya tetap merekomendasikan UUIDv7. Saya hanya ingin Anda tahu apa yang Anda tandatangani.

Ringkasan untuk pembaca non-teknis

  • Jenis nomor ID baru, UUIDv7, populer karena menjaga database tetap cepat dan tetap menghindari tabrakan.
  • Setiap ID membawa waktu pembuatan di dalamnya. Ini praktis, tetapi juga berarti siapa pun yang melihat ID bisa tahu kira-kira kapan sesuatu dibuat, dan waktunya tidak selalu akurat.
  • Ia label internal yang bagus dan rahasia yang buruk. Jangan pernah dipakai sebagai link layaknya password.
  • Tanyakan ke tim teknis Anda: “Apakah ada link publik, atau logika pengurutan, yang bergantung pada ID ini berurutan menurut waktu?”

Kenapa UUIDv7 bagus

Nilai UUIDv4 yang acak mendarat di mana-mana di indeks B-tree. Insert mengenai halaman acak, halaman terpecah, cache jadi dingin. UUIDv7 menaruh timestamp milidetik di bit tinggi, sehingga ID baru mendarat di dekat ujung indeks seperti auto-increment, sambil tetap unik tanpa koordinator pusat.

Susunan bit UUIDv7: timestamp milidetik 48 bit, bit versi dan varian, dan hingga 74 bit acak di mana 42 bit adalah counter di Python.

Python 3.14 menambahkan uuid.uuid7() ke standard library. Menurut dokumentasinya, ia menyematkan timestamp 48 bit dan memakai counter 42 bit untuk menjaga ID tetap monoton dalam satu milidetik.

Temuan artikelnya

Dari tulisan tersebut dan RFC 9562:

Diagram tes lompatan jam: setelah jam sistem digeser mundur satu jam, timestamp uuid7 berjalan sekitar satu jam di depan waktu nyata dan selisihnya terus membesar.

  • RFC mengizinkan implementasi mengubah timestamp, dan menyatakan tidak ada jaminan seberapa dekat nilainya dengan waktu nyata.
  • Implementasi juga boleh memajukan timestamp melewati jam nyata demi menjaga urutan.
  • Pada tes penulis dengan uuid7() Python, jam sistem digeser mundur satu jam. Timestamp yang tertanam lalu berjalan sekitar satu jam di depan waktu nyata, dan selisihnya terus membesar saat ID dibuat dalam volume besar.
  • Satu-satunya jaminan yang dipercaya penulis di semua implementasi adalah penghindaran tabrakan dan keunikan.

Dokumentasi PostgreSQL mengatakan hal serupa: timestamp yang diekstrak belum tentu sama dengan saat UUID dibuat, tergantung implementasinya.

Kata para praktisi

Thread Hacker News tentang UUIDv7 sebagai primary key, yang lebih lama tetapi masih relevan, menunjukkan perpecahan pendapatnya dengan baik.

  • “Membocorkan waktu itu tidak masalah.” Satu komentator berargumen bahwa dengan pengecekan otorisasi yang benar, ID yang bisa diprediksi tidak berbahaya, dan waktu pembuatan jarang berarti bagi kebanyakan perusahaan.
  • “74 bit acak itu cukup.” Yang lain mencatat bahwa bagian acaknya jauh lebih besar daripada kebanyakan secret key yang dipakai orang, jadi menebak ID tidak praktis.
  • “ID campuran membocorkan lebih banyak.” Orang ketiga menunjukkan bahwa mencampur v4 dan v7 bisa memberi tahu pihak luar resource mana yang dianggap sensitif oleh tim, dan memaksakan konsistensi di tim besar adalah pekerjaan nyata.
  • “Pagination adalah oracle.” Seseorang mencatat bahwa cursor seperti id > some_value bisa disalahgunakan tanpa men-decode apa pun.
  • “Enkripsi yang publik.” Seorang administrator database menyarankan menyimpan v7 secara internal dan mengekspos identifier terenkripsi atau terpisah ke luar.

Pendapat saya

Para pragmatis benar soal menebak dan para pihak yang berhati-hati benar soal metadata. Itu dua pertanyaan berbeda, dan debatnya jadi keruh ketika keduanya dicampur.

Saya akan memakai UUIDv7 sebagai primary key internal tanpa banyak ragu. Ini peningkatan nyata untuk tabel yang banyak operasi tulis, dan biayanya kecil kalau timestamp diperlakukan sebagai petunjuk.

Di mana saya tidak setuju dengan “membocorkan waktu itu tidak masalah”: itu keputusan kebijakan, bukan default teknis. Untuk tiket support, boleh. Untuk akun, order, rekam medis, atau laporan whistleblower, waktu pembuatan bisa mengungkap hal yang tidak pernah Anda putuskan untuk dipublikasikan. Ambil keputusannya dengan sengaja.

Saya juga merasa keluhan soal “jam” agak dibesar-besarkan dalam praktik, tetapi tetap layak diuji. Jam yang mundur satu jam jarang terjadi di server yang sehat, tetapi VM bisa di-pause, NTP bisa salah konfigurasi, dan container bisa dimigrasi. Kalau kode Anda mengurutkan berdasarkan ID untuk arti “terbaru”, Anda bergantung pada sesuatu yang tidak pernah dijanjikan spesifikasi. Kolom created_at hampir tanpa biaya dan menghilangkan keraguan itu.

Untuk tim: pilih UUIDv7 untuk key, kolom timestamp untuk waktu, dan token acak untuk akses. Tiga pekerjaan, tiga tool.

Coba dalam 15 menit

1. Urutan dalam tight loop

import uuid

ids = [uuid.uuid7() for _ in range(200_000)]
out_of_order = sum(1 for a, b in zip(ids, ids[1:]) if b < a)
print("out of order:", out_of_order)

Hasilnya seharusnya nol dalam satu proses di Python 3.14. Lalu jalankan padanannya di library yang benar-benar Anda deploy. Tidak semua implementasi menjamin ini.

2. Banyak proses

# gen.py
import uuid

for _ in range(100_000):
    print(uuid.uuid7())
for i in 1 2 3 4; do python gen.py > out_$i.txt & done; wait
cat out_*.txt | sort | uniq -d | wc -l
for f in out_*.txt; do sort -c "$f" && echo "$f sorted"; done

Duplikat seharusnya nol, dan setiap file seharusnya berurutan. Aliran gabungan lintas proses hanya kira-kira berurutan menurut waktu, karena tiap proses punya counter sendiri.

3. Decode apa yang dibocorkan ID Anda

import uuid, datetime

u = uuid.uuid7()
print(u)
print(datetime.datetime.fromtimestamp(u.time / 1000, tz=datetime.timezone.utc))

Sekarang ambil ID dari sistem Anda sendiri. Apakah ia ada di URL, link email, atau API publik? Siapa pun yang memegangnya tahu kapan objek itu dibuat.

4. Jangan pernah dipakai sebagai secret

UUIDv7 punya paling banyak 74 bit acak, dan di Python sebagian darinya adalah counter. Jangan pakai sebagai reset token, session ID, atau “link yang tidak bisa ditebak”:

import secrets
print(secrets.token_urlsafe(32))

Aturan praktis

PekerjaanPakai
Primary key di database AndaUUIDv7
”Kapan ini terjadi”Kolom created_at
Apa pun yang memberi aksesToken acak
Identifier publikPutuskan dengan sengaja apakah waktu pembuatan boleh bocor

Tabel aturan praktis: UUIDv7 untuk primary key, created_at untuk waktu, token acak untuk akses, keputusan yang disengaja untuk identifier publik.

Belajar lebih lanjut

Pertanyaan

Apakah UUIDv7 di sistem Anda adalah key yang buram, atau ada query, cursor, atau laporan yang diam-diam mengasumsikan ID itu berurutan menurut waktu?

Pertanyaan yang sering diajukan

Apakah UUIDv7 cocok sebagai primary key database?
Ya untuk tabel yang banyak operasi tulis, karena timestamp di bit tinggi membuat insert mendarat di dekat ujung indeks sementara ID tetap unik tanpa koordinator pusat. Penulis akan memakainya sebagai primary key internal tanpa banyak ragu.
Apakah UUIDv7 membocorkan kapan sebuah record dibuat?
Ya. Siapa pun yang memegang ID bisa men-decode timestamp di dalamnya, yang mungkin tidak persis. Untuk akun, order, atau rekam medis, putuskan dengan sengaja apakah waktu pembuatan boleh bocor.
Bisakah UUIDv7 dipakai sebagai secret token atau link reset?
Tidak. Ia punya paling banyak 74 bit acak, dan di Python sebagian darinya adalah counter. Pakai secrets.token_urlsafe(32).
Bisakah mengurutkan berdasarkan UUIDv7 untuk mendapat yang terbaru?
Tidak dengan aman. Spesifikasi tidak pernah menjanjikan timestamp sama dengan waktu nyata, dan pada tes yang dikutip jam yang digeser mundur satu jam mendorong timestamp sekitar satu jam di depan waktu nyata. Kolom created_at menghilangkan keraguan itu.
Bagikan Bagikan ke X Bagikan ke LinkedIn

About the author

Portrait of Kiell Tampubolon

Security Engineer & Technical Writer

Security engineer and technical writer based in Batam, Indonesia. I review and harden MCP servers and AI agents, build security automation, and write up what holds and what fails. I also train on DNS security as a PANDI .id Academy trainer.

All writing | RSS | Markdown