UUID v4 vs v7 — Farklar ve Her Birini Ne Zaman Kullanmalı
UUID v4, on yıldan fazla süredir dağıtık birincil anahtarlar için varsayılan seçim olmuştur. Rastgele 128 bitlik bir değer üretin, sekiz onaltılık grup olarak biçimlendirin, bitti. Koordinasyon gerekmez, pratikte sıfır çakışma olasılığı, her yerde çalışır. Peki neden UUID v7 — 2024'te RFC 9562'de standartlaştırıldı — 2026'da üretim sistemlerine hızla yayılıyor?
Kısa cevap: veritabanı performansı. UUID v4 B-tree dizini yerelliğini yok eder. UUID v7, geliştiricilerin UUID'ler hakkında sevdiği her şeyi korurken bunu düzeltir. Bu makale her sürümün gerçekten ne olduğunu, farkın ölçekte neden önemli olduğunu, her birinin ne zaman seçileceğini ve kesintisiz nasıl geçileceğini açıklar.
Şimdi UUID üretmeniz mi gerekiyor? Toplu olarak hem v4 hem de v7'yi destekleyen Toova UUID generator'ı deneyin. Diğer rastgele tanımlayıcılar için, rastgele dizgi üreteci ve parola üreteci daha kısa belirteçleri kapsar.
UUID v4 — Saf Rastgelelik
UUID sürüm 4, 128 bitin 122'sini doldurmak için kriptografik olarak güvenli bir sözde rastgele sayı üreteci (CSPRNG) kullanır. Kalan altı bit sabittir: dört bit sürümü (0100) kodlar ve iki bit varyantı (10) kodlar. Sonuç şöyle görünür:
f47ac10b-58cc-4372-a567-0e02b2c3d479
^^^^
sürüm = 4 (rastgele) Rastgelelik özelliktir. İki bağımsız sistem koordinasyon olmadan UUID üretebilir ve asla çakışmaz — 2,71 katrilyon v4 UUID setinde bir çakışma olasılığı yaklaşık %50'dir, bu da pratik herhangi bir uygulama için riskin ihmal edilebilir olduğu anlamına gelir. Merkezi bir kimlik sunucusuna, bir veritabanı dizisine veya dağıtık bir kilide ihtiyacınız yoktur.
v4 nasıl üretilir
import { v4 as uuidv4 } from 'uuid';
const id = uuidv4();
// => 'f47ac10b-58cc-4372-a567-0e02b2c3d479' uuid kütüphanesi (JavaScript), Python'un uuid.uuid4()'ü, Go'nun google/uuid'si ve her büyük dil çalışma zamanı OS CSPRNG'sine yetki verir — Linux'ta /dev/urandom, Windows'ta CryptGenRandom. Üretim maliyeti etkin olarak sıfırdır.
Sorun: rastgele ekleme B-tree dizinlerini öldürür
Bir B-tree dizini veriyi sıralı tutar. Yeni bir satır eklediğinizde, veritabanı yeni anahtarın sıralı düzende nereye uyduğunu bulur ve oraya yerleştirir. Her yeni anahtar rastgeleyse, dizinde rastgele bir konuma düşer — bu da her eklemenin diskten farklı bir sayfayı arabellek havuzuna yüklemesi gerektiği anlamına gelir. Düşük hacimde bu görünmezdir. Yüksek hacimde (milyonlarca satır, yüksek INSERT oranı), dizin parçalanması adı verilen bir desen oluşturur: dizin, her ekleme farklı bir konuma vurduğu için yarı boş sayfalarla dolar ve sıcak çalışma seti dizinin tamamına yayıldığı için arabellek havuzu sürekli karışır, öngörülebilir bir yakın dilim yerine.
Üretimdeki belirtiler: INSERT gecikmesi artar, autovacuum yükü artar (PostgreSQL), checkpoint baskısı büyür ve "yakın" dizinde herhangi bir yerelliğe eşlenmediği için yakın kayıtlar için okuma performansı bozulur. Bu varsayımsal değildir — UUID v4 birincil anahtarları olan büyük PostgreSQL ve MySQL tablolarında iyi belgelenmiş bir acı noktasıdır.
UUID v7 — Zaman Sıralı Rastgelelik
UUID v7, B-tree parçalanma sorununu çözmek için açıkça tasarlandı. En önemli bitlere 48 bitlik bir Unix milisaniye zaman damgası kodlar, ardından sürüm bitleri, 12 rastgele bit, varyant bitleri ve 62 rastgele bit daha gelir. Toplam rastgelelik: 74 bit — hâlâ çakışmaları önlemek için gerekenden çok daha fazla.
018f4e6b-a23c-7d45-9abc-0e02b2c3d479
^^^^^^^^^^^^^^
48 bit Unix zaman damgası (ms hassasiyet)
^
sürüm = 7 Zaman damgası yüksek bitleri işgal ettiği için, daha sonra üretilen UUID'ler daha önce üretilenlerden sonra sıralanır. Eklemeler her zaman dizinin sağ kenarına eklenir. Veritabanının yalnızca en son dizin sayfasını arabellek havuzunda sıcak tutması gerekir, tüm dizini değil. Yüksek INSERT oranlarında, bu tek başına yazma gecikmesini %30-60 azaltabilir ve onlarca milyon satırlı tablolarda I/O'yu bir büyüklük sırası azaltabilir.
v7 nasıl üretilir
import { v7 as uuidv7 } from 'uuid';
const id = uuidv7();
// => '018f4e6b-a23c-7d45-9abc-0e02b2c3d479'
Aynı uuid kütüphanesi sürüm 10'da v7 desteği ekledi. Python'un standart kütüphanesi 3.14'te ekledi. PostgreSQL 17, uuidv7()'yi yerleşik bir fonksiyon olarak içerir. Daha eski bir yığında iseniz, birkaç küçük kütüphane bağımlılık olmadan v7 üretimi sağlar.
Milisaniye altı monotonisite
Aynı milisaniye içinde iki v7 UUID üretildiğinde ne olur? RFC 9562, uygulamaların aynı milisaniye içinde sıralamayı garanti etmek için rastgele bitlerde monotonik bir sayacı artırmasına izin verir. uuid kütüphanesi bunu varsayılan olarak yapar. Sonuç: bir milisaniyede 10.000 kimlik üretilse bile, yine de doğru şekilde sıralanırlar.
Ayrıntıda B-Tree Dizin Parçalanma Sorunu
Bunun neden önemli olduğunu anlamak için, 100 milyon mevcut satırlı bir tabloda UUID v4 birincil anahtarı ile saniyede 10.000 eklemede ne olduğunu düşünün:
- Her ekleme, 100 milyon mevcut girdi arasında rastgele bir konuma düşen rastgele bir 128 bitlik anahtar üretir.
- Veritabanı, bu konumu içeren belirli B-tree sayfasını arabellek havuzuna yüklemelidir.
- 100 milyon satır ve 8 KB sayfa ile dizin yaklaşık 100.000 sayfaya yayılır. Her saniyede 10.000 farklı sayfa gereklidir — tipik bir 8 GB shared_buffers'ın yalnızca bu dizin için tutabileceğinden çok daha fazla.
- Her önbellek kaçırması bir disk okumasına neden olur. 10.000 ekleme/sn'de, bu büyük tablolarda SSD'leri bile doyuran saniyede binlerce rastgele disk okuması üretebilir.
UUID v7 ile, saniyede 10.000 eklemenin tümü en sağdaki yaprak sayfaya (veya bir avuç son sayfaya) düşer. Arabellek havuzunun yalnızca o birkaç sayfayı sıcak tutması gerekir. Yazma için önbellek isabet oranı %100'e yaklaşır. Yazma yükseltmesi dramatik bir şekilde düşer.
Aynı fayda aralık taramaları için de geçerlidir: bir v4 tablosunda WHERE created_at BETWEEN x AND y tam bir dizin taraması veya ayrı bir zaman damgası dizini gerektirir. Bir v7 tablosunda, birincil anahtarın kendisi zaman damgası dizinidir — sorgu doğrudan doğru aralığa atlayabilir.
PostgreSQL'de UUID v7 Nasıl Kullanılır
-- PostgreSQL 16+'da UUID türü ile yerel olarak çalışır
CREATE TABLE events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- v4 (rastgele)
-- Uzantı veya uygulama tarafı üretim ile UUIDv7'ye geçin
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- UUIDv7 ile: zaman damgası zaten gömülüdür, bu yüzden
-- bu ayrı created_at sütunu genellikle gereksizdir.
PostgreSQL 17, uuidv7()'yi yerel olarak içerir. PostgreSQL 14-16 için, pg_uuidv7 uzantısı aynı fonksiyonu sağlar. UUID veri türü, v4 ve v7'yi özdeş olarak depolar — 16 bayt, ek yük yok. Tek fark, sıralama düzenini belirleyen bit desenidir.
Yararlı bir sonuç: zaman damgası gömülü olduğu için, birçok tablonun artık sıralama veya görüntüleme için ayrı bir created_at sütununa ihtiyacı yoktur. Tek bir fonksiyon çağrısıyla bir v7 UUID'sinden zaman damgasını çıkarabilirsiniz. Bu, şema karmaşıklığını azaltır ve ekleme başına bir yazmayı ortadan kaldırır.
UUID v4 vs v7 — Ödünler
| Özellik | UUID v4 | UUID v7 |
|---|---|---|
| Rastgelelik bitleri | 122 | 74 |
| Sıralama düzeni | Rastgele | Kronolojik |
| B-tree INSERT performansı | Kötü (parçalanma) | Mükemmel (sıralı) |
| Zaman damgası sızıntısı | Yok | Evet (ms hassasiyet) |
| RFC standardı | RFC 4122 (2005), RFC 9562 (2024) | RFC 9562 (2024) |
| Kütüphane desteği | Evrensel | Hızla büyüyor (2024-2026) |
| Gömülü created_at | Hayır | Evet |
Geçiş Kılavuzu — v4'ten v7'ye
Mevcut bir tabloyu UUID v4'ten v7 birincil anahtarlarına taşımak çok adımlı bir işlemdir. Anahtar kısıtlama: yabancı anahtarlar tarafından başvurulan bir birincil anahtarın değerini, başvuran tüm tabloları da güncellemeden değiştiremezsiniz. Bir bakım penceresi planlayın veya çift yazma yaklaşımını kullanın.
-- 1. Yeni sütun ekle
ALTER TABLE orders ADD COLUMN id_v7 UUID;
-- 2. Mevcut satırları doldur (orijinal created_at'i
-- zaman damgası kaynağı olarak koru; uygulamanızda UUIDv7 kütüphane fonksiyonu kullanın)
UPDATE orders SET id_v7 = generate_uuidv7(created_at);
-- 3. NULL kalmadığını doğrula
SELECT COUNT(*) FROM orders WHERE id_v7 IS NULL;
-- 4. Sütunları değiştir (kısa bir bakım penceresi gerektirir)
ALTER TABLE orders ALTER COLUMN id_v7 SET NOT NULL;
ALTER TABLE orders ALTER COLUMN id_v7 SET DEFAULT generate_uuidv7(now());
ALTER TABLE orders RENAME COLUMN id TO id_v4_old;
ALTER TABLE orders RENAME COLUMN id_v7 TO id;
ALTER TABLE orders ADD PRIMARY KEY (id); Yüksek trafikli tablolarda kesintisiz geçişler için önerilen yaklaşım:
- İleride v7 UUID'leri üreten bir sunucu varsayılanıyla yeni
id_v7sütununu ekleyin. - v7 zaman damgası kısmının tohumu olarak mevcut
created_atzaman damgasını kullanarak eski satırları düşük trafik dönemlerinde toplu olarak doldurun. - Başvuran tablolardaki tüm yabancı anahtar sütunlarını
id_v7'ye işaret edecek şekilde güncelleyin. - Sütunları yeniden adlandırın ve kısa bir bakım penceresinde eski birincil anahtar kısıtlamasını düşürün.
Doldurma adımı en uzun olanıdır. Toplu başına 10.000 satır ve toplu arasında 50 ms uyku ile, 100 milyon satırlı bir tablo yaklaşık 8 saat alır. Erken başlayın.
Gerçek Dünya Etkisi
Birkaç mühendislik ekibi üretim boyutundaki veri kümelerinde UUID v4 ve v7'yi karşılaştıran kıyaslamalar yayınladı. Tutarlı bulgular:
- INSERT verimi: v4'ten v7'ye geçerken 50M+ satırlı tablolarda 2-5 kat iyileşme, tablo boyutu büyüdükçe kazanım artar.
- Yazma gecikmesi p99: aynı donanımda yüklerden (v4) yüzlerce milisaniyeden (yük altında) tek haneli milisaniyelere (v7) düşer.
- Dizin boyutu: v7 sütunlarındaki B-tree dizinleri, parçalanma daha az yarı boş sayfa bıraktığı için aynı verideki eşdeğer v4 dizinlerinden %15-30 daha küçüktür.
- Arabellek havuzu verimliliği: birincil anahtar dizini için paylaşılan arabellekler isabet oranı, yalnızca yakın sayfaların sıcak kalması gerektiği için ~%40'tan (v4, büyük tablo) ~%99'a (v7) çıkar.
Kazanımlar yaklaşık 1 milyon satırın altında ihmal edilebilirdir. Tablonuz küçük kalırsa, basitlik için v4'e bağlı kalın. 10 milyon satırın üzerinde anlamlı bir INSERT oranıyla, v7 daha iyi varsayılandır.
Her Birini Ne Zaman Kullanmalı
Şu durumlarda UUID v7 kullanın:
- Yeni bir şema tasarlıyorsunuz ve tablo büyüyecek (10M+ satır).
- Tablonun yüksek INSERT oranı vardır — olaylar, loglar, siparişler, mesajlar, bildirimler.
- Bir oluşturma zaman damgası olarak da hizmet eden bir birincil anahtar istiyorsunuz (bir sütunu ortadan kaldırır).
- PostgreSQL 17, MySQL 8.0+ veya v7 üretimini destekleyen modern bir ORM kullanıyorsunuz.
- ID'ye göre sıralama, oluşturma zamanına göre sıralamaya anlamsal olarak eşdeğerdir — ki bu çoğu ekleme ağırlıklı tablo için olacaktır.
Şu durumlarda UUID v4 kullanın:
- Tanımlayıcı kullanıcılara ifşa edilir ve oluşturma zamanını ortaya çıkarmamalıdır (davet kodları, paylaşım bağlantıları, faturalama tutamaçları).
- Tablo küçük ve istikrarlıdır — hiçbir performans avantajı geçiş maliyetini haklı çıkarmaz.
- Oluşturma zaman damgasının hassas olduğu bir bağlamda kimlikler üretiyorsunuz (büyüme optikleriyle rekabet eden bir üründe özel kullanıcı kayıtları).
- Bir kerelik kimlik bilgileri veya belirteçler olarak bir şey istiyorsunuz — herhangi bir UUID sürümü değil, özel bir sır üreteci kullanın.
Özet
UUID v4 rastgele, gizli ve evrensel olarak desteklenir. UUID v7 zaman sıralı, veritabanı dostu ve şimdi büyük kütüphanelerde ve veritabanlarında standart. Büyük veya hızlı büyüyen tablolarla yeni şemalar için, v7 daha iyi varsayılandır. Kullanıcılara ifşa edilen ve zaman damgası sızıntısının bir endişe olduğu kimlikler için, v4 doğru seçim olmaya devam ediyor.
Toova UUID generator ile her iki sürümü de anında üretin — hesap gerekmez. Daha kısa belirteçler için, rastgele dizgi üreteci herhangi bir uzunlukta alfasayısal kimlikler üretir.