Pembuat UUID

Buat UUID satu per satu atau lima puluh sekaligus: v4 acak atau v7 terurut waktu, yang stempel waktunya menjaga urutan dan lebih cocok jadi kunci basis data.

Versi

122 bit acak. Tak mengungkap apa pun tentang kapan ia dibuat.

Berapa banyak

Membuat…

Apa itu UUID dan mengapa ia ada

UUID — Universally Unique Identifier, disebut juga GUID dalam dokumentasi Microsoft — adalah nilai 128-bit yang ditulis sebagai 32 digit heksadesimal dalam pengelompokan 8-4-4-4-12 yang familiar. Seluruh tujuannya adalah membiarkan sistem terpisah mencetak pengenal secara mandiri, tanpa koordinasi di antara mereka, dan tetap yakin hasilnya tak akan bertumbukan. Itulah yang membedakannya dari kolom penambah-otomatis basis data: dua server, dua klien seluler yang luring di pesawat, dan pekerjaan latar semuanya bisa membuat catatan pada saat yang sama tanpa meminta izin siapa pun.

Keunikan di sini bersifat probabilistik ketimbang terjamin. Versi 4 menyisakan 122 bit untuk keacakan, yang merupakan ruang cukup besar sehingga menghasilkan miliaran nilai masih menyisakan peluang pengulangan jauh di bawah peluang cakram diam-diam merusak datanya. Dalam praktik Anda bisa memperlakukannya sebagai unik; matematikanya bukan mata rantai lemahnya.

Versi 4 vs. versi 7 — pilihan yang penting

Versi 4 acak dari ujung ke ujung. Ia tak membawa informasi apa pun: bukan kapan ia dibuat, bukan oleh siapa, bukan dalam urutan apa. Itu entah kekuatan terbesarnya atau cacat utamanya, bergantung di mana Anda menaruhnya.

Versi 7, distandarkan dalam RFC 9562 pada 2024, mengganti 48 bit pertama dengan stempel waktu Unix milidetik dan mengisi sisanya dengan keacakan. Karena waktunya datang lebih dulu dan nilainya dibaca dari kiri ke kanan, mengurutkan pengenal v7 sebagai teks polos juga mengurutkannya secara kronologis.

Ini bukan perbedaan kosmetik. Basis data menyimpan kunci utama dalam indeks B-tree yang terurut. Sisipkan kunci v7 dan tiap baris baru mendarat di tepi kanan pohon, di samping yang sebelumnya — halaman yang Anda tulisi tetap di memori dan indeks tumbuh dengan rapi. Sisipkan kunci v4 dan tiap penulisan mendarat pada posisi acak, jadi basis data menyentuh halaman berbeda tiap kali, tingkat cache-hit jatuh dan indeks terfragmentasi. Pada tabel besar dan sibuk, perbedaan throughput sisipan itu substansial, itulah sebabnya v7 diadopsi begitu cepat untuk kunci utama.

  • Pilih v7 untuk kunci utama basis data, pengenal peristiwa dan log, dan apa pun yang ingin Anda urutkan atau kueri berdasarkan rentang waktu pembuatan.
  • Pilih v4 ketika pengenal muncul di suatu tempat tak tepercaya dan tak boleh membocorkan apa pun — termasuk fakta bahwa satu catatan dibuat tepat sebelum yang lain.
  • Keduanya baik untuk ID korelasi, kunci idempotensi, atau nama berkas, tempat pengurutan tak penting.

Imbangannya persis kebocoran itu: pengenal v7 memberi tahu siapa pun yang melihatnya, hingga milidetik, kapan ia dibuat. Untuk ID baris itu biasanya tak berbahaya dan sering berguna. Untuk token setel ulang sandi atau tautan berbagi publik itu adalah informasi yang tak Anda maksudkan untuk diterbitkan — dan itu seharusnya bukan UUID sama sekali, melainkan token acak dari pembangkit rahasia khusus.

Pengurutan dalam milidetik yang sama

Detail halus yang menjebak banyak implementasi v7: perangkat keras modern menghasilkan jauh lebih dari satu pengenal per milidetik. Jika dua nilai berbagi stempel waktu, urutannya diputuskan oleh bit acak yang mengikutinya — yang berarti, secara acak. Hasilkan lima puluh dalam gelung ketat dan Anda mendapatkan lima puluh nilai yang hanya kira-kira terurut, kehilangan persis sifat yang karenanya Anda memilih v7.

RFC 9562 mengatasi ini dengan pencacah monotonik, dan alat ini mengimplementasikannya: 12 bit tepat setelah stempel waktu mencacah ke atas dalam satu milidetik, jadi batch meningkat ketat ketimbang kira-kira. Jika pencacah penuh — lebih dari 4.096 nilai dalam milidetik yang sama — pembangkit meminjam milidetik berikutnya alih-alih membungkus dan memancarkan nilai yang terurut sebelum pendahulunya. Ia menangani jam yang bergerak mundur, yang terjadi dengan koreksi NTP, dengan cara yang sama.

Membaca nilai v7 dari kiri ke kanan, mengambil 0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b sebagai contohnya:

  • 0190a1b2-c3d4 — stempel waktu Unix 48-bit dalam milidetik. Karena ia datang lebih dulu, urutan teks adalah urutan waktu.
  • 7 — nibble versi, yang menjadikan ini v7 ketimbang v4.
  • e5f — pencacah monotonik 12-bit, menambah dalam satu milidetik.
  • 8 — bit varian, ditetapkan RFC 9562 untuk setiap UUID modern (selalu 8, 9, a, atau b).
  • a9b-0c1d2e3f4a5b — 62 bit sisanya, murni acak.

Menyimpan dan memakai UUID

Bentuk kanonisnya adalah huruf kecil dengan tanda hubung, dan RFC 9562 mengatakan pembangkit sebaiknya memancarkan persis itu — itulah sebabnya alat ini tak menawarkan opsi pemformatan. Anda masih akan menemui ejaan lain di alam bebas: huruf besar dan dibungkus kurung kurawal dalam perkakas Microsoft, dan tanpa tanda hubung tempat seseorang menginginkan kolom lebih pendek. Semuanya adalah 128 bit yang sama, dan perbandingan sebaiknya tak peka besar-kecil huruf.

Yang penting adalah penyimpanan. UUID adalah 16 bita, tetapi bentuk teksnya 36 karakter — jadi menyimpannya sebagai string lebih dari menggandakan ruang dalam baris dan, yang lebih penting, dalam setiap indeks yang menyertakannya. Pakai tipe asli bila tersedia:

uuid                      -- PostgreSQL: native 16-byte type
BINARY(16)                -- MySQL: compact; CHAR(36) wastes 20 bytes/row
uniqueidentifier          -- SQL Server
crypto.randomUUID()       // JavaScript: v4 only, needs a secure context
uuid.uuid4() / uuid7()    # Python: stdlib v4; v7 via a library

Satu peringatan terakhir: UUID mengidentifikasi, ia tak mengizinkan. Karena mereka tak bisa ditebak, ada godaan memperlakukan URL tak terdaftar yang berisi satu sebagai privat. Tetapi pengenal bocor — melalui log, riwayat peramban, header perujuk, dan tangkapan layar — jadi apa pun yang benar-benar butuh dilindungi tetap butuh pemeriksaan izin nyata di baliknya.

Cara mengetahui apakah UUID itu v4 atau v7

Pengenal biasanya sampai ke tangan Anda tanpa catatan yang menyebut asalnya, dan catatan itu memang tak diperlukan: versinya tertulis di dalam nilai itu sendiri. Keduanya sama-sama 32 digit heksadesimal dalam pengelompokan 8-4-4-4-12 yang sama, jadi bedanya bukan pada bentuk — bedanya pada dua digit tunggal di posisi tetap, dan sisanya mengikuti dari sana.

  • Digit pertama kelompok ketiga adalah nibble versi. Angka 4 di sana berarti versi 4, angka 7 berarti versi 7, dan tak ada bagian lain dari nilai itu yang ikut menentukan.
  • Digit pertama kelompok keempat membawa bit varian dan bernilai 8, 9, a, atau b pada kedua versi — jadi ia tak pernah memberi tahu Anda sedang memegang yang mana. Yang ia beri tahu adalah bahwa nilai itu memang mengikuti RFC 9562; apa pun selain itu di posisi tersebut adalah tata letak yang lebih tua, atau bukan UUID.
  • Bila nibble versi bernilai 7, dua belas digit pertama adalah waktu pembuatan: cacahan 48-bit milidetik sejak awal 1970, ditulis heksadesimal.
  • Bila bernilai 4, tak ada lagi yang bisa dibaca. Versi 4 tidak menyandikan waktu, mesin, maupun urutan, dan justru itulah sifat yang membuat Anda memilihnya.

Ambil nilai yang dibedah bagian di atas, 0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b. Kelompok ketiganya dibuka angka 7, jadi ia versi 7, dan dua belas digit pertamanya adalah 0190a1b2c3d4 — ubah bilangan heksadesimal itu ke desimal, serahkan ke Konverter stempel waktu Unix, dan Anda mendapat suatu sore di Juli 2024. Di sebelahnya, 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d membuka kelompok ketiganya dengan angka 4, dan dua belas digit pertamanya sendiri adalah data acak yang tak terpecahkan menjadi apa pun. Keduanya sepakat tepat pada satu hal: sama-sama membuka kelompok keempat dengan salah satu dari empat digit yang diizinkan bit varian.

Apakah v7 setahan v4 terhadap tumbukan?

Pertanyaan yang wajar, sebab v7 memang membawa keacakan lebih sedikit. Versi 4 membelanjakan 122 dari 128 bitnya untuk data acak. Versi 7 membelanjakan 48 untuk stempel waktu dan, di sini, 12 lagi untuk pencacah monotonik, sehingga tersisa 62 bit acak — sedikit lebih dari separuhnya. Dibaca sebagai angka telanjang, itu tampak seperti kemunduran serius.

  • Di dalam satu batch dari alat ini, pengulangan bukan tak mungkin terjadi melainkan mustahil. Nilai yang berbagi milidetik memperoleh nilai pencacah yang berbeda, dan nilai yang tak berbagi milidetik membawa stempel waktu yang berbeda, jadi tak ada dua yang bisa sama — itu aritmetika, bukan peluang.
  • Antara dua mesin yang menghasilkan pada saat yang sama, peluangnya paling buruk adalah masalah ulang tahun atas 62 bit, yang berimbang kira-kira pada akar kuadrat ruangnya: pada kisaran dua miliar nilai, dan semuanya di dalam satu milidetik yang sama.
  • Antara milidetik yang berbeda, tumbukan v7 bukan sekadar tak mungkin terjadi melainkan mustahil, sebab digit terdepannya sendiri sudah berbeda.

Jadi perbandingan yang jujur bukan 122 bit lawan 62. Perbandingannya adalah satu undian yang ditarik berulang-ulang sepanjang umur sistem lawan undian terpisah yang jauh lebih kecil, digelar di dalam tiap milidetik dan dibuang begitu milidetik itu berakhir. Susunan kedua justru yang lebih kuat, dan alasan memilih v4 tetap seperti yang diberikan bagian perbandingan — bukan tumbukan, melainkan bahwa v7 mengumumkan dengan lantang kapan ia dibuat.

Memindahkan tabel yang sudah ada dari v4 ke v7

Pertanyaan yang menyusul setelah memilih v7 adalah apa yang harus dilakukan pada baris yang sudah ada di tabel, dan bagian yang melegakan adalah kolomnya sama sekali tak perlu berubah. Kedua versi adalah 128 bit yang sama dalam bentuk teks 36 karakter yang sama, jadi kolom uuid di PostgreSQL, BINARY(16), atau CHAR(36) menampung campuran itu tanpa menyadarinya. Anda mulai menghasilkan v7 untuk baris baru dan berhenti di situ; tak ada langkah migrasi dan tak ada pengisian mundur.

  • Yang langsung didapat: setiap baris yang disisipkan mulai sekarang membawa stempel waktu di depan, sehingga kunci baru mendarat berdampingan di satu ujung indeks alih-alih berhamburan di sepanjangnya. Manfaat ini menyangkut ke mana penulisan baru pergi, dan ia sudah ada sejak sisipan pertama.
  • Yang tak pernah datang: baris yang sudah ada tetap tanpa urutan selamanya. Tak ada yang bisa menaruh waktu pembuatan pada nilai yang tak pernah diberi waktu, dan menerbitkan ulang setiap pengenal berarti menulis ulang setiap kunci asing yang menunjuk kepadanya — pekerjaan yang jauh lebih besar daripada mengganti pembangkit, dan jarang sepadan hanya demi indeks.
  • Yang perlu diawasi: mengurutkan kolom itu berhenti berarti satu hal. Cacahan milidetik adalah bilangan kecil untuk ruas 48 bit, jadi kunci v7 berkumpul dalam pita sempit di bagian bawah rentang sementara kunci v4 tersebar di seluruh rentang, dan sesekali satu di antaranya jatuh di tengah pita itu.

Butir terakhir itulah yang menggigit, sebab kueri yang mengurutkan berdasarkan kunci tampak benar pada data baru dan diam-diam salah melaporkan data lama. Bila Anda butuh satu urutan untuk seluruh tabel, tambahkan kolom waktu pembuatan dan urutkan berdasarkan kolom itu, lalu biarkan pengenal kembali menjadi pengenal. Setidaknya campuran itu masih terbaca selama prosesnya: nibble versi duduk di setiap nilai, jadi kueri bisa memisahkan kedua era tanpa kolom kedua bila memang harus.

Pertanyaan yang sering diajukan

Apakah saya sebaiknya memakai v4 atau v7?
Pakai v7 untuk kunci utama basis data dan apa pun yang akan Anda urutkan berdasarkan waktu pembuatan: stempel waktu di depan menjaga sisipan bergerombol di ujung indeks alih-alih tersebar. Pakai v4 ketika pengenal tak boleh mengungkap apa pun, termasuk kapan ia dibuat.
Apakah dua UUID pernah sama?
Mungkin tetapi teramat kecil kemungkinannya. Versi 4 punya 122 bit acak, jadi bahkan setelah menghasilkan miliaran nilai probabilitas tumbukan tetap jauh di bawah probabilitas penyimpanan diam-diam merusaknya.
Apa yang terjadi pada versi 1, 3, dan 5?
Versi 1 mengodekan stempel waktu dan alamat MAC mesin, yang membocorkan identitas perangkat keras dan tak bisa dihasilkan di peramban sama sekali. Versi 3 dan 5 menurunkan UUID secara deterministik dari ruang-nama dan nama memakai MD5 atau SHA-1 — berguna ketika masukan yang sama harus selalu menghasilkan pengenal yang sama, tetapi pekerjaan berbeda dari menghasilkan yang baru.
Apakah UUID cukup aman untuk dipakai sebagai token rahasia?
UUID v4 tak bisa ditebak, tetapi yang v7 secara terbuka mengodekan waktu pembuatannya, dan tak satu pun dimaksudkan sebagai kredensial. Untuk setel ulang sandi, token sesi, atau tautan berbagi, hasilkan rahasia acak khusus dan periksa izin di server ketimbang mengandalkan pengenal yang sulit ditebak.
Mengapa batch v7 saya tak terurut sempurna di alat lain?
Karena banyak implementasi melewati pencacah monotonik. Ketika beberapa nilai berbagi satu milidetik, urutannya jatuh ke bit acak yang mengikuti. Alat ini mengimplementasikan pencacah RFC 9562, jadi batch yang dihasilkan di sini meningkat ketat.
Bagaimana saya sebaiknya menyimpan UUID dalam basis data?
Dalam tipe asli 16 bita bila tersedia — uuid di PostgreSQL, uniqueidentifier di SQL Server, BINARY(16) di MySQL. Menyimpan bentuk teks 36 karakter alih-alih lebih dari menggandakan ruang yang dipakai dalam baris dan dalam setiap indeks yang menyertakan kolomnya.
Apakah ini dihasilkan di server Anda?
Tidak. Mereka dihasilkan di peramban Anda memakai crypto.getRandomValues, sumber acak kriptografis platform — yang sama yang dipakai crypto.randomUUID. Tak ada nilai yang pernah dikirim ke mana pun, dan memuat ulang halaman menghasilkan kumpulan yang sama sekali baru.
Bisakah saya tahu kapan UUID v7 dibuat?
Bisa, dan Anda tak butuh apa pun selain nilainya. Dua belas digit heksadesimal pertamanya adalah cacahan milidetik sejak awal 1970: ubah ke desimal dan serahkan hasilnya ke Konverter stempel waktu Unix. Versi 4 tak punya ruas seperti itu, jadi dua belas digit yang sama di sana bersifat acak dan tak terpecahkan menjadi apa pun.
Apakah bit acak v7 lebih sedikit daripada v4?
Ya — 62 di sini melawan 122 milik v4, karena stempel waktu dan pencacah memakan tempatnya. Itu tak membuat tumbukan lebih mungkin dalam praktik: dua nilai v7 hanya bisa bertumbukan bila dibuat dalam milidetik yang sama, jadi 62 bit itu dibelanjakan di dalam satu milidetik dan bukan sepanjang umur sistem, dan di dalam satu batch dari alat ini pencacah membuat pengulangan mustahil, bukan sekadar tak mungkin terjadi.
Bisakah UUID v4 dan v7 berada di kolom yang sama?
Bisa. Keduanya 128 bit yang sama dalam bentuk teks yang sama, jadi tak ada yang berubah pada skema dan tak ada migrasi — Anda menghasilkan v7 mulai sekarang dan membiarkan baris lama apa adanya. Satu-satunya yang perlu diawasi adalah pengurutan: baris baru tersusun menurut urutan pembuatan di antara mereka, tetapi baris lama yang acak tersebar di sekelilingnya, jadi mengurutkan berdasarkan kunci bukanlah urutan waktu bagi tabel secara keseluruhan.
Apa itu UUID versi 6 dan 8?
RFC 9562 mendefinisikan keduanya di samping v7. Versi 6 adalah versi 1 dengan ruas stempel waktunya ditata ulang agar nilainya terurut kronologis, ditujukan bagi sistem yang sudah terikat pada v1 — RFC itu menyatakan bahwa selain itu sebaiknya memakai v7. Versi 8 adalah slot yang sengaja dibiarkan terbuka untuk tata letak buatan sendiri, yang hanya bit versi dan bit variannya tetap sementara 122 sisanya Anda yang menentukan. Alat ini tidak menghasilkan keduanya.

Alat terkait