CodeGym /Kursy /SQL SELF /Generowanie unikalnych identyfikatorów

Generowanie unikalnych identyfikatorów

SQL SELF
Poziom 16 , Lekcja 0
Dostępny

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ł GUIDGlobally 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: UUID zajmuje 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 email
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.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION