UUIDv7 Bagus untuk Primary Key, Buruk sebagai Jam: 4 Tes Sebelum Migrasi
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.

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:

- 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_valuebisa 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
| Pekerjaan | Pakai |
|---|---|
| Primary key di database Anda | UUIDv7 |
| ”Kapan ini terjadi” | Kolom created_at |
| Apa pun yang memberi akses | Token acak |
| Identifier publik | Putuskan dengan sengaja apakah waktu pembuatan boleh bocor |

Belajar lebih lanjut
- RFC 9562, untuk redaksi persis soal timestamp dan counter.
- Tulisan UUIDv7 aslinya, untuk melihat tes lompatan jam secara lengkap.
- Dokumentasi fungsi UUID PostgreSQL, lalu jalankan
EXPLAINpada query Anda sendiri alih-alih memercayai benchmark orang lain.
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.
About the author
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.
Artikel terkait
-
8 min read
Cooldown 1 Hari Memblokir 70% Rilis npm yang Dibajak di 2026. Untuk Typosquat, 7 Hari Masih Meloloskan 45%
Saya memutar ulang 11.556 paket npm dan PyPI berbahaya 2026 terhadap cooldown dependensi. Pembajakan cepat mati, typosquat tidak, dan perbaikan ikut tertunda.
- Security Engineering
- Engineering Practice
-
9 min read
A 1-Day Cooldown Would Have Blocked 70% of 2026's Hijacked npm Releases. Against Typosquats, 7 Days Still Misses 45%
I replayed 11,556 malicious npm and PyPI packages from 2026 against a dependency cooldown. Hijacks die fast, typosquats don't, and fixes pay the bill.
- Security Engineering
- Engineering Practice
-
9 min read
Python 3.15 Is Out. I Checked the Top 500 PyPI Packages: 97% Install From a Wheel, 12 Still Run Build Scripts
I classified the latest release of the 500 top PyPI packages for Python 3.15. 485 install from a wheel; 12 fall back to running build code, led by PyYAML.
- Engineering Practice
- Security Engineering
All writing | RSS | Markdown