Kiedy komputery zaczęły się masowo łączyć w sieci, pojawił się prosty, ale mega ważny problem: jak zagwarantować, że dwa różne urządzenia, znajdujące się na różnych końcach świata, nie wygenerują tego samego identyfikatora?
Wyobraź sobie: dwa serwery, jeden w Tokio, drugi w Berlinie, niezależnie tworzą identyfikatory dla obiektów. Jeśli nagle wygenerują takie samo ID — dane mogą się pomieszać, nadpisać, a system się wywali.
Tak więc w latach 90., w czasach szybkiego rozwoju systemów rozproszonych i protokołów sieciowych, w czeluściach Microsoft i Open Software Foundation (OSF) narodził się pomysł GUID — Globally Unique Identifier, czyli globalnie unikalny identyfikator.
GUID (a w standardzie ISO — UUID, Universally Unique Identifier) — to 128-bitowa liczba, która wygląda na przykład tak:
550e8400-e29b-41d4-a716-446655440000
To taki cyfrowy odcisk palca: jest tak długi i losowy, że szansa na kolizję (czyli powtórzenie się dwóch identyfikatorów) jest praktycznie zerowa.
Tworzy się go z użyciem:
- czasu,
- losowych liczb,
- adresu MAC urządzenia (w starszych wersjach),
- a nawet kryptograficznych funkcji hashujących.
Dlaczego to było ważne? Chodzi o to, że GUID pozwolił tworzyć unikalne identyfikatory bez centralnego serwera, bez koordynacji, bez blokad i opóźnień. To było prawdziwe wybawienie dla:
- rozproszonych baz danych,
- protokołów sieciowych,
- systemów obiegu dokumentów,
- i oczywiście nowoczesnych API.
UUID w PostgreSQL
GUID/UUID jest używany wszędzie — od PostgreSQL po chmurę. Stały się niewidzialnymi budowniczymi współczesnego internetu: bez nich nie moglibyśmy tak łatwo łączyć świata.
W praktyce to po prostu bardzo długa losowa liczba z 16 bajtów, zapisana w formacie szesnastkowym. Po prostu bardzo długa liczba całkowita.
Ten typ danych jest idealny, jeśli musisz zagwarantować unikalność wartości w całym systemie, bez zależności od centralnego generatora identyfikatorów. To szczególnie przydatne w systemach rozproszonych albo gdy dane są generowane na różnych serwerach.
Dlaczego nie używać po prostu INTEGER?
Można by pomyśleć, po co UUID, skoro można po prostu użyć autoinkrementującej liczby jako identyfikatora? Sprawdźmy:
Globalna unikalność: Jeśli twoja baza działa na kilku serwerach, zagwarantowanie unikalności INTEGER jest trudne. Z UUID ten problem znika.
Bezpieczeństwo i ukrywanie danych: UUID trudniej przewidzieć niż kolejny numer. To zmniejsza ryzyko wycieku info przez przewidywalne ID (np. /users/1, /users/2).
Systemy rozproszone: Jeśli dane powstają w różnych częściach systemu, autoinkrementujący INTEGER nie daje rady bez skomplikowanej synchronizacji.
Kolejna zaleta UUID — to standard, wspierany w wielu językach programowania i systemach bazodanowych.
Zalety używania UUID
Główne plusy:
- Unikalność: masz pewność, że identyfikator jest unikalny, nawet jeśli dane powstają na różnych serwerach czy systemach.
- Elastyczność: możesz używać do kluczy głównych, obcych i innych rzeczy.
- Skalowalność: wygodne przy pracy z rozproszonymi bazami danych.
Ale UUID ma też swoje minusy:
- Rozmiar:
UUIDzajmuje więcej miejsca w pamięci (16 bajtów) niżINTEGER(4 bajty). - Czytelność: trudniej to przeczytać i zapamiętać.
Generowanie UUID w PostgreSQL
Wbudowana funkcja gen_random_uuid()
W PostgreSQL od wersji 13 jest wbudowana funkcja gen_random_uuid() do generowania losowych UUID. Ta funkcja zwraca unikalny identyfikator, który możesz użyć jako wartość dla kolumny typu UUID.
Przykład:
SELECT gen_random_uuid();
Wynik:
d17fc23b-22e5-4fcb-bf86-1b4c766d77b7
Upewnij się, że rozszerzenie pgcrypto jest zainstalowane (dla PSQL 1-12)
W starszych wersjach PostgreSQL (przed 13) funkcja gen_random_uuid() jest dostępna po zainstalowaniu rozszerzenia pgcrypto. Jeśli w pracy każą ci z tego korzystać, możesz się uratować, wykonując komendę:
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
To pozwoli ci korzystać z generowania losowych UUID.
Użycie UUID jako klucza obcego
UUID świetnie nadaje się do tworzenia powiązań między tabelami. Załóżmy, że masz tabelę użytkowników:
| id | name | |
|---|---|---|
| d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | Alice | alice@example.com |
| a1d3e15a-abc1-4b51-a320-2d4c859f7467 | Bob | bob@example.com |
| 3c524998-5c24-4e73-836d-a4c6bb3cafcd | Charlie | charlie@example.com |
Tworzenie tabeli orders
Stwórzmy tabelę orders, gdzie user_id będzie kluczem obcym wskazującym na id w tabeli users.
| order_id | user_id | order_date |
|---|---|---|
| 1a5b7d9c-b1a2-4f8e-9e7a-0a1111111111 | d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | 2024-10-15 10:00:00 |
| 2b6c8e0d-c2b3-5a9f-af8b-1b2222222222 | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-15 10:05:00 |
| 3c7d9f1e-d3c4-6baf-bc9c-2c3333333333 | 3c524998-5c24-4e73-836d-a4c6bb3cafcd | 2024-10-15 10:10:00 |
| 4d8eaf2f-e4d5-7cb0-cdab-3d4444444444 | d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | 2024-10-15 10:15:00 |
| 5e9fb030-f5e6-8dc1-debc-4e5555555555 | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-15 10:20:00 |
Pole user_id jest powiązane z polem id tabeli users, co pozwala tworzyć relacje między użytkownikami a ich zamówieniami.
Pobieranie danych z JOIN
Zobaczmy, jak powiązane są dane w tabelach users i orders:
SELECT
u.id AS user_id,
u.name,
o.order_id,
o.order_date
FROM users u
JOIN orders o ON u.id = o.user_id;
Wynik:
| user_id | name | order_id | order_date |
|---|---|---|---|
| d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | Alice | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-20 12:34:56 |
Typowe scenariusze użycia UUID
Identyfikatory użytkowników i zamówień: w systemach rozproszonych, gdzie dane mogą pochodzić z różnych źródeł.
Znaczniki dla API: UUID często używa się w REST API do identyfikacji encji.
Globalna synchronizacja danych: na przykład, gdy dane zbierane są z różnych serwerów.
Typowe błędy i niuanse
Próba ręcznego generowania UUID: lepiej używać wbudowanych funkcji, takich jak gen_random_uuid(), żeby uniknąć błędów.
Nadmierne użycie: nie stosuj UUID tam, gdzie wystarczy autoinkrementujący INTEGER. Na przykład w lokalnych tabelach, które nigdy nie będą skalowane.
Rozmiar: UUID zajmuje więcej miejsca, co może wpływać na wydajność zapytań, zwłaszcza przy indeksowaniu.
GO TO FULL VERSION