UUID v4 / UUID v7 / ULID perusteellinen vertailu: kuinka tasapainottaa aikajärjestys, tehokkuus ja luettavuus
UUID:t ja ULID:t ovat keinoja jakaa “globaalisti yksilöllisiä” tunnisteita hajautetuissa järjestelmissä ja tietokannoissa. Ne näyttävät ensisilmäyksellä samalta, mutta standardoinnin, tallennustehokkuuden, ihmisen luettavuuden ja tietovuotoriskin osalta eroja riittää. Tässä artikkelissa vertaan kolmea hallitsevaa lähestymistapaa – UUID v4:ää, UUID v7:ää ja ULID:ia – ja lopuksi kokoan huomioita myös UUID v1:stä ja UUID v6:sta.
Seuraavat työkalut hoitavat tunnisteiden luonnin ja aikaleimojen purun kokonaan selaimessa; käyttöliittymä on toistaiseksi japaniksi/englanniksi.
- UUID v4 -generointi
- UUID v7 -generointi
- UUID v7 -aikaleiman lukeminen
- ULID-generointi
- ULID-aikaleiman lukeminen
UUID v4: puhdas satunnaisuus
UUID v4 käyttää 122 bittiä 128 bitistä satunnaisuuteen, joten törmäyksen todennäköisyys on astronomisen pieni. Kääntöpuolena on, että arvot eivät järjesty aikajärjestykseen, jolloin B-puuindeksit hajoavat usein sivuiksi ja lisäysten paikallisuus kärsii. v4 sopii istuntotunnisteisiin, kertakäyttöisiin avaimiin ja muihin tilanteisiin, joissa “täydellinen satunnaisuus” on tavoite.
UUID v7: aikajärjestyksessä etenevä evoluutio
UUID v7 standardoitiin vuonna 2024 (RFC 9562). Sen ensimmäiset 48 bittiä ovat UNIX-epookkia millisekunneissa, loppu täytetään satunnaisuudella. Lexikografinen järjestys (merkkijonovertailu) vastaa tällöin luontijärjestystä, joten v7 toimii erinomaisesti pääavaimena – indeksin paikallisuus säilyy. Se mahtuu suoraan myös olemassa oleviin uuid
-tyyppeihin tai BINARY(16)
-sarakkeisiin.
- Satunnaisuusbudjetti: version ja variantin hallintabittien jälkeen käytössä on noin 74 bittiä satunnaisuutta. Moni toteutus tekee lisäksi monotonisia säätöjä välttääkseen törmäyksiä saman millisekunnin sisällä; entropia riittää silti hyvin.
- Tietovuoto: tunnisteesta voi päätellä luontiajan millisekunnin tarkkuudella. Jos satunnaisuus on heikkoa ja tunnisteita syntyy valtavasti, lähekkäisten arvojen arvaaminen helpottuu. Sisäisissä järjestelmissä tämä yleensä hyväksytään, mutta julkisissa päätepisteissä järjestyksen paljastuminen voi olla riski.
ULID: ihmisläheinen tunniste
ULID on vuodesta 2016 alkaen yleistynyt de facto -standardi. Esitysmuotona on 26 merkkiä pitkä Crockfordin Base32, josta on karsittu helposti sekoittuvat merkit (O/I/L/1), joten se sopii hyvin URL-osoitteisiin ja kopiointiin. Kuten v7, myös ULID:n ensimmäiset 48 bittiä ovat aikaleimaa (ms), joten lexikografinen järjestys vastaa aikajärjestystä.
- Lajittelu: ULID-merkkijonot järjestyvät aina aikajärjestykseen, ja laajalti käytetty monotoninen generointi minimoi törmäyksiä.
- Tallennusmuoto:
TEXT(26)
pitää esityksen luettavana, mutta binaarinen tallennus edellyttää Base32↔16 tavun muunnoksia. Moni relaatiotietokantojenUUID
-tyyppi ei tue ULID-arvoja sellaisenaan. - Tietovuoto: aivan kuten v7, ULID paljastaa aikaleiman (ms). Jos et halua API-käyttäjien päättelevän jakelujärjestystä, harkitse vaihtoehtoja.
Vertailutaulukko (käytännön näkökulma)
Ominaisuus | UUID v4 | UUID v7 | ULID |
---|---|---|---|
Standardointi | RFC 4122 | RFC 9562 (2024) | De facto, ei standardia |
Bittirakenne | 128 bittiä joista 122 satunnaista | 48-bit UNIX ms + loppu satunnaista (monotonia mahdollista) |
48-bit UNIX ms + 80-bit satunnaista |
Satunnaisuuden määrä | ≈122 bittiä | ≈74 bittiä (version/variantin jälkeen) | 80 bittiä |
Merkkimuoto | 36 merkkiä (heksadesimaali + yhdysmerkit) | 36 merkkiä (heksadesimaali + yhdysmerkit) | 26 merkkiä (Crockford Base32) |
Luonnollinen järjestys (teksti) | ✗ (satunnainen) | ✓ (lexikografinen = aikajärjestys) | ✓ (lexikografinen = aikajärjestys) |
Luonnollinen järjestys (binaari) | ✗ | ✓ (BINARY(16) nousee aikajärjestyksessä) |
✓ (kun 6 tavun aikaleima on big-endian ennen satunnaisjaksoa) |
Tietokantayhteensopivuus | uuid / BINARY(16) ovat ihanteellisia |
uuid / BINARY(16) ovat ihanteellisia |
TEXT(26) säilyttää luettavuuden; BINARY(16) vaatii muunnoksen ja monen UUID -tyypin tuki puuttuu |
Indeksin paikallisuus | Heikko (satunnaislisäykset kuormittavat) | Hyvä (lähes peräkkäiset lisäykset, kuitenkin hot spot -riski) | Hyvä (sama huomio kuin v7:ssä) |
Tasa-arvovertailun kustannus | Matala (16 tavun vertailu) | Matala (16 tavun vertailu) | TEXT vertailu on raskaampaa; BINARY kevyt |
Koodausrasite | Heksadesimaali↔16 tavua (kevyt) | Heksadesimaali↔16 tavua (kevyt) | Base32↔16 tavua (raskaampi) |
Luettavuus / URL-kelpoisuus | Matala | Matala | Korkea |
Tietovuoto | Ei | Aikaleima (ms) | Aikaleima (ms) |
Tyypilliset käyttökohteet | Istuntotunnisteet, kertakäyttöiset avaimet | Tietokantojen pääavaimet, tapahtumatunnisteet, lokien järjestys | Julkiset tunnisteet ja lokit, joissa luettavuus auttaa |
Kuuma-alueen varoitus v7:lle/ULID:lle: jos kaikki lisäykset osuvat yhdelle shardille tai johtajalle, peräkkäiset lisäykset voivat silti kuumentaa B-puun lehtiä. Etubittien kevyellä sekoituksella (“prefix shuffle”) tai yhdistämällä tunniste toiseen shardiavaimeen kuormaa voi tasata.
Tietokantatoteutusten muistiinpanot (PostgreSQL / MySQL / SQLite)
- PostgreSQL
- v4/v7:
uuid
-tyyppi on optimi. Kun tuot v7:n tekstinä ja castaatuuid
:ksi, saat luonnollisen järjestyksen. - ULID: käytä
char(26)
/text
-sarakeita taibytea(16)
-sarjoja Base32-muunnoksen jälkeen.
- v4/v7:
- MySQL / InnoDB
BINARY(16)
on kompakti ja nopea v4/v7:lle. v7 säilyy aikajärjestyksessä big-endian-muodossa. ULID sopiiCHAR(26)
-sarjoihin taiBINARY(16)
-sarjoihin muunnoksen kanssa.
- SQLite
- Natiivia UUID-tyyppiä ei ole. Käytä
BLOB(16)
- taiTEXT
-sarakkeita. Indeksoidut BLOBit toimivat riittävän hyvin.
- Natiivia UUID-tyyppiä ei ole. Käytä
Tietoturvanäkökulmia
- Arvattavuus: v7 ja ULID jakavat samat aikaleimabitit. Jos luot runsaasti tunnisteita saman millisekunnin sisällä ja satunnaislähde on heikko, lähiarvojen ennustettavuus kasvaa. Käytä kryptografisesti turvallista PRNG:tä ja pidä monotoniset säädöt tasapainossa.
- Metadatan vuoto: tunniste paljastaa luontiajan ja karkean jakaumavauhdin. Julkisissa API:ssa harkitse sisäisten ja ulkoisten tunnisteiden erottamista.
Yhteenveto: valintaperusteet
- UUID v4: puhdas satunnaisuus. Ei järjestystä. Teoreettiset törmäykset ovat käytännössä olemattomia. Sopii istuntotunnisteisiin, CSRF-tokeneihin ja vastaaviin.
- UUID v7: standardoitu järjestetty UUID. Erinomainen sisäisiin järjestelmiin ja tietokantojen pääavaimiksi. Monotoninen generointi tekee törmäyksistä käytännössä mahdottomia.
- ULID: verrattain ihmisläheinen. Hyvä valinta URL-osoitteisiin ja lokien luettavuuteen, mutta sisäisenä pääavaimena v7 on usein mukavampi. Monotoninen generointi estää törmäyksiä käytännössä.
Liite: UUID v1 ja v6 (lyhyesti)
-
UUID v1 (aikapohjainen + MAC) 60 bitin aikaleima (100 ns) ja solmuidentiteetti (usein MAC-osoite). Tarjoaa vahvan aikajärjestyksen, mutta paljastaa potentiaalisesti hostin MAC-osoitteen ja vaatii huolellisen kellon takaisinkelausten käsittelyn. Yksityisyyssyistä sitä vältetään nykyisin usein.
-
UUID v6 (uudelleen järjestetty v1) Järjestelee v1:n aikaleiman big-endian-muotoon lajiteltavuuden parantamiseksi. Historiallisesti sitä ehdotettiin “lajiteltavaksi v1:ksi”, mutta standardointi on käytännössä kääntynyt v7:ään. Uusissa suunnitelmissa v7 on suositeltavampi kuin v6.
Toteutuksen tarkistuslista
- Käytä kryptografisesti turvallista PRNG:tä satunnaisuuteen.
- Kun käytät v7/ULID:n monotonista generointia, varmista ettei satunnaisuuden vinoutta synny samalla kun vältät saman millisekunnin törmäykset.
- Suosi
uuid
/BINARY(16)
-sarakkeita, jotta vältyt merkkijonosarakkeiden kollaatioiden kustannuksilta. - Päätä ulkoisen tunnistepolitiikan periaatteet (sallitaanko jakelujärjestyksen paljastuminen?). Erottele sisäiset ja ulkoiset tunnisteet tarvittaessa.
Johtopäätös: tämän päivän työkaluilla UUID v7 on oletusvalinta sisäisiksi pääavaimiksi, kun taas ULID on vahva, jos luettavuus tai perintöjärjestelmän vaatimukset painavat. v4 tai muut vaihtoehdot jäävät erityistapauksiin, joissa aikaleiman paljastuminen ei tule kyseeseen.