- UUID v4 memiliki tingkat keacakan yang tinggi sehingga memicu inefisiensi indeks dan I/O berlebihan, dan jika digunakan sebagai kunci utama di PostgreSQL dapat menurunkan performa
- Karena penyisipan berlangsung secara acak, page split dan fragmentasi indeks lebih sering terjadi, serta menyebabkan ukuran log WAL membesar dan latensi tulis meningkat
- UUID berukuran 16 byte, dua kali lebih besar daripada bigint, yang berujung pada penurunan cache hit ratio dan pemborosan memori
- Sering disalahpahami sebagai pengenal yang aman, tetapi menurut RFC 4122, UUID bukan sarana keamanan untuk mencegah tebakan
- Untuk database baru, disarankan menggunakan kunci berbasis sequence bertipe integer, dan bila tak terhindarkan, gunakan UUID v7 yang berurutan berdasarkan waktu
Masalah performa UUID v4
- Database PostgreSQL yang menggunakan kunci utama UUID v4 selama 10 tahun terakhir secara konsisten menunjukkan penurunan performa dan I/O berlebihan
- UUID v4 menghasilkan 122 bit acak sehingga indeks tidak bisa diurutkan
- Saat penyisipan, data tidak disimpan ke halaman yang berurutan sehingga terjadi akses acak, dan saat update maupun delete juga diperlukan penelusuran yang tidak efisien
- Indeks B-Tree mengasumsikan data terurut, tetapi UUID v4 tidak memiliki keterurutan sehingga efisiensi insert rendah
- Setiap insert ditulis ke halaman acak sehingga page split di tengah sering terjadi
- Akibatnya muncul latensi tulis dan peningkatan WAL
Struktur UUID dan alternatifnya
- UUID adalah pengenal berukuran 128 bit (16 byte), dan di PostgreSQL disimpan sebagai tipe binary uuid
- UUID v4 berbasis bit acak, sedangkan UUID v7 menyertakan timestamp pada 48 bit pertama sehingga efisiensi indeks lebih baik
- PostgreSQL 18 (direncanakan pada 2025) akan mendukung UUID v7 secara bawaan
- UUID v7 dapat diurutkan secara kronologis sehingga kepadatan halaman dan efisiensi cache meningkat
Alasan memilih UUID dan keterbatasannya
- UUID digunakan saat dibutuhkan pembuatan pengenal tanpa benturan di lingkungan multi-klien atau microservices
- Contoh: membuat ID secara bersamaan di beberapa instance database
- Namun, RFC 4122 menyatakan “jangan menganggap UUID sulit ditebak”, sehingga tidak cocok sebagai pengenal keamanan
- Probabilitas benturan mencapai 50% setelah menghasilkan 2.71×10¹⁸ UUID; dalam praktiknya peluang benturan rendah, tetapi biaya performanya tinggi
Inefisiensi ruang dan I/O pada UUID
- UUID memakan ruang dua kali lipat dari bigint (8 byte) dan empat kali lipat dari int (4 byte)
- Pada tabel besar, hal ini menyebabkan kebutuhan penyimpanan meningkat serta waktu backup dan restore bertambah
- Hasil eksperimen kepadatan halaman indeks
- indeks integer: 97.64%
- indeks UUID v4: 79.06%
- indeks UUID v7: 90.09%
- Dalam pengujian Cybertec, pencarian pada indeks UUID v4 membutuhkan tambahan 8.5 juta akses halaman, dengan I/O naik 31229%
- Dalam kondisi yang sama, indeks bigint membutuhkan 27,332 akses buffer, sedangkan UUID v4 membutuhkan 8,562,960 akses buffer
Dampak pada cache dan memori
- Karena distribusinya acak, UUID memiliki buffer cache hit ratio yang rendah
- Lebih banyak halaman harus dimuat ke cache, dan halaman yang dibutuhkan lebih sering mengalami eviction
- Penurunan efisiensi cache menimbulkan latensi query dan kenaikan penggunaan memori
- Untuk menjaga performa, disarankan melakukan rekonstruksi indeks berkala (
REINDEX CONCURRENTLY) atau menggunakan pg_repack
Cara mengurangi dampak performa
- Menambah memori: disarankan menyediakan RAM 4 kali ukuran database (contoh: DB 25GB → memori 128GB)
- Menyesuaikan
work_mem: performa dapat meningkat dengan mengalokasikan lebih banyak memori untuk operasi sort
- Di lingkungan Rails, gunakan pengaturan
implicit_order_column agar memakai kolom yang bisa diurutkan seperti created_at, bukan UUID
- Dengan perintah
CLUSTER, tabel dapat ditata ulang berdasarkan kolom yang bisa diurutkan, tetapi memerlukan exclusive lock
Rekomendasi kunci integer dan sequence
- Untuk database baru, disarankan memakai kunci berbasis sequence bertipe integer
integer (4 byte) menyediakan sekitar 2 miliar nilai unik, sedangkan bigint (8 byte) menyediakan jauh lebih banyak
- Sebagian besar aplikasi bisnis sudah cukup dengan integer, sementara layanan berskala besar lebih cocok menggunakan bigint
- Sebagai alternatif yang realistis selain UUID v4, gunakan UUID v7 atau ekstensi sequential_uuids
Ringkasan
- UUID v4 menyebabkan inefisiensi indeks, I/O tinggi, dan efisiensi cache rendah karena sifatnya yang acak
- UUID v4 tidak dapat digunakan sebagai pengenal keamanan dan juga boros ruang
- Kunci sequence bertipe integer lebih cocok untuk sebagian besar aplikasi
- Jika UUID memang harus digunakan, pilih UUID v7 yang berurutan berdasarkan waktu
- Sebaiknya hindari penggunaan
gen_random_uuid() sebagai kunci utama di PostgreSQL
Belum ada komentar.