Czym jest UUID i dlaczego bywa nazywany GUID
UUID, czyli universally unique identifier, to 128-bitowa liczba zapisywana jako 32 znaki szesnastkowe w pięciu grupach rozdzielonych myślnikami. Cały pomysł opiera się na jednym założeniu. Identyfikator powstaje lokalnie, bez pytania serwera ani bazy danych o kolejny numer, a mimo to prawdopodobieństwo kolizji z już istniejącym jest znikome.
W dokumentacji Microsoftu ten sam format nosi nazwę GUID, od globally unique identifier. Obie nazwy opisują tę samą 128-bitową liczbę i w praktyce używa się ich wymiennie, z tą różnicą, że narzędzia Microsoftu częściej zapisują ją w nawiasach klamrowych.
Rozwiązuje to konkretny problem znany z autonumeracji. Przy sekwencji w bazie identyfikator powstaje dopiero po zapisie rekordu, więc aplikacja musi czekać na odpowiedź. Uniwersalnie unikalne identyfikatory istnieją od razu, można je przypisać w przeglądarce i wysłać w komplecie z danymi. W systemach rozproszonych, gdzie kilkanaście usług zapisuje dane niezależnie od siebie i żadna nie ma pewności, która zdąży pierwsza, wspólny licznik stałby się wąskim gardłem, więc każdy węzeł generuje identyfikatory sam, a scalenie zbiorów sprowadza się do zwykłego złączenia tabel.
Wersja 4 i kryptograficzny generator liczb losowych
W wersji 4 losowe są wszystkie bity poza sześcioma. Cztery z nich kodują numer wersji, dwa wariant. Zostaje 122 bity losowości, czyli około 5,3 · 10³⁶ możliwych kombinacji. Skalę łatwiej wyczuć na przykładzie, bo gdyby na całym świecie powstawał miliard identyfikatorów na sekundę, pierwszego powtórzenia można by się spodziewać dopiero po mniej więcej 85 latach.
O bezpieczeństwie takiego identyfikatora decyduje źródło losowości, a generator liczb losowych używany w tym narzędziu pochodzi z systemu operacyjnego i jest przeznaczony do zastosowań kryptograficznych. Implementacje oparte na zwykłym generatorze pseudolosowym bywały w przeszłości źródłem realnych podatności, bo znając kilka wyników, dało się przewidzieć kolejne, a UUID często pełni funkcję tajnego odnośnika do zasobu.
Wersja 7 i identyfikator, który się sortuje
Jako klucz główny w bazie danych wersja 4 ma jedną poważną wadę. Indeks typu B-drzewo lubi wartości rosnące, bo nowe rekordy trafiają wtedy na koniec i strony indeksu wypełniają się równo. Losowy UUID wstawia się w przypadkowe miejsca, więc baza raz po raz dzieli zapełnione strony, indeks rośnie szybciej i gorzej mieści się w pamięci podręcznej. Przy dużych tabelach różnica w szybkości wstawiania bywa kilkukrotna.
Wersja 7, opisana w RFC 9562 z maja 2024 roku, rozwiązuje to prosto. Pierwsze 48 bitów zajmuje znacznik czasu w milisekundach, kolejnych sześć przypada na wersję i wariant, a pozostałe 74 bity pochodzą z generatora losowego. Identyfikatory rosną w czasie, więc zachowują się w indeksie jak zwykła autonumeracja, a nadal powstają po stronie aplikacji. Cena jest jedna i widać ją od razu, bo z identyfikatora v7 da się odczytać moment jego utworzenia z dokładnością do milisekundy. Tam, gdzie to problem, wersja 4 pozostaje właściwym wyborem.
Jak rozpoznać wersję i wariant
Wersja siedzi w pierwszym znaku trzeciej grupy, czyli w trzynastym znaku całego zapisu. Jeżeli widzisz tam czwórkę, masz UUID v4; siódemka oznacza v7. Wariant kodują dwa najstarsze bity dziewiątego bajtu, czyli siedemnasty znak zapisu, i dla standardu opisanego w RFC musi to być 8, 9, a albo b. Znaki spoza tego zbioru wskazują na identyfikator ze starszej specyfikacji Microsoftu albo na błąd generatora.
Walidator w tym narzędziu sprawdza jedno i drugie, a przy wersji 7 odczytuje znacznik czasu i pokazuje datę utworzenia. To wygodny sposób na zorientowanie się, z jakiego okresu pochodzi rekord, gdy w bazie nie ma osobnej kolumny z datą.
Gdzie używa się identyfikatorów UUID
Najczęstsze zastosowanie to klucz główny w bazie danych, ale UUID rozszedł się daleko poza bazy. W API klient tworzy zasób i sam nadaje mu identyfikator, więc powtórzone żądanie po zerwanym połączeniu nie zakłada drugiego rekordu. W kolejkach komunikatów identyfikator wiadomości odróżnia powtórkę od nowego zdarzenia.
Druga duża grupa zastosowań to korelacja logów. Usługa, która przyjmuje żądanie, nadaje mu identyfikator i przekazuje go dalej w nagłówku, a każdy kolejny komponent dopisuje ten sam ciąg do swoich wpisów. Prześledzenie jednej operacji przez kilkanaście maszyn sprowadza się wtedy do wyszukania jednego ciągu znaków, a oprogramowanie do zbierania logów zwykle rozpoznaje taki nagłówek samo. Poza serwerownią te same identyfikatory trafiają do nazw plików przesyłanych przez użytkowników i oznaczają pojedynczą instalację programu na komputerze. Sam identyfikator nie niesie żadnej informacji o osobie, bo w wersji 4 są to wyłącznie losowe bity.
UUID zerowy i jego zastosowania
Identyfikator złożony wyłącznie z zer jest w standardzie wyróżniony jako nil UUID. Formalnie nie ma ani wersji, ani wariantu, a mimo to pozostaje zapisem zgodnym ze specyfikacją. Używa się go tam, gdzie potrzebna jest wartość oznaczająca „brak identyfikatora”, a typ kolumny nie dopuszcza wartości pustej, na przykład w danych testowych albo jako wartość domyślna przed przypisaniem właściwego klucza.
RFC 9562 definiuje też wartość przeciwną, złożoną z samych znaków f, nazywaną max UUID. Bywa przydatna jako górna granica przy zapytaniach zakresowych po kluczu głównym.