JavaRush /Курсы /SQL SELF /Генерация уникальных идентификаторов

Генерация уникальных идентификаторов

SQL SELF
16 уровень , 0 лекция
Открыта

Когда компьютеры только начали активно соединяться в сети, возникла простая, но очень острая проблема: как гарантировать, что два разных устройства, находящиеся в разных частях света, не сгенерируют один и тот же идентификатор?

Представьте себе: два сервера, один в Токио, другой в Берлине, независимо создают идентификаторы для объектов. Если они вдруг создадут одинаковые ID — данные могут перепутаться, перезаписаться, а система рухнуть.

Так в 1990-х, в эпоху бурного развития распределённых систем и сетевых протоколов, в недрах Microsoft и Open Software Foundation (OSF) родилась идея GUIDGlobally Unique Identifier, или глобально уникальный идентификатор.

GUID (а в стандарте ISO — UUID, Universally Unique Identifier) — это 128-битное число, выглядящее, например, вот так:

550e8400-e29b-41d4-a716-446655440000

Это как цифровой отпечаток: он настолько длинный и хаотичный, что вероятность коллизии (совпадения двух идентификаторов) практически нулевая.

Создаётся он с использованием:

  • времени,
  • случайных чисел,
  • MAC-адреса устройства (в старых версиях),
  • и даже криптографических хэш-функций.

Почему это было важно? Дело в том, что GUID позволил создавать уникальные идентификаторы без центрального сервера, без координации, без блокировок и задержек. Это стало настоящим спасением для:

  • распределённых баз данных,
  • сетевых протоколов,
  • систем документооборота,
  • и, конечно, современных API.

UUID в PostgreSQL

GUID/UUID используется повсеместно — от PostgreSQL до облачных сервисов. Они стали невидимыми строителями современного интернета: без них мы бы не смогли так просто объединять мир.

Фактически это просто очень длинное случайное число из 16 байт, которое записано в 16-тиричном формате. Просто очень длинное целое число.

Этот тип данных идеально подходит, если вам нужно гарантировать уникальность значений на уровне всей системы, без зависимости от централизованного генератора идентификаторов. Это особенно полезно в распределённых системах или когда данные генерируются на разных серверах.

Почему не использовать просто INTEGER?

Казалось бы, зачем нужен UUID, если можно просто использовать автоинкрементирующееся число как идентификатор? Давайте разберёмся:

Глобальная уникальность: Если бы ваша база данных работала на нескольких серверах, гарантировать уникальность INTEGER будет сложно. С UUID эта проблема решается.

Безопасность и скрытие данных: UUID труднее предугадать, чем последовательный номер. Это снижает риск утечки информации через предсказуемые идентификаторы (например, /users/1, /users/2).

Распределённые системы: Если данные генерируются в разных частях системы, автоинкрементирующий INTEGER не подходит без сложной синхронизации.

Ещё одно преимущество UUID — это стандарт, поддерживаемый во многих языках программирования и системах хранения данных.

Преимущества использования UUID

Основные плюсы:

  • Уникальность: гарантируется уникальность идентификатора, даже если данные создаются на разных серверах или системах.
  • Гибкость: можно использовать для первичных ключей, внешних ключей и других задач.
  • Масштабируемость: удобно при работе с распределёнными базами данных.

Однако у UUID есть и свои недостатки:

  • Размер: UUID занимает больше места в памяти (16 байт), чем INTEGER (4 байта).
  • Читаемость: сравнительно сложнее читать и запоминать.

Генерация UUID в PostgreSQL

Встроенная функция gen_random_uuid()

В PostgreSQL с версии 13 появилась встроенная функция gen_random_uuid() для генерации случайных UUID. Эта функция возвращает уникальный идентификатор, который можно использовать как значение для столбца типа UUID.

Пример:

SELECT gen_random_uuid();

Результат:

d17fc23b-22e5-4fcb-bf86-1b4c766d77b7

Убедитесь, что расширение pgcrypto установлено (для PSQL 1-12)

В ранних версиях PostgreSQL (до 13-й версии) функция gen_random_uuid() доступна после установки расширения pgcrypto. Если на работе вас заставляют им пользоваться, то вы можете спасти ситуацию, выполнив команду:

CREATE EXTENSION IF NOT EXISTS "pgcrypto";

Это позволит использовать генерацию случайных UUID.

Использование UUID в качестве внешнего ключа

UUID можно удобно использовать для построения связей между таблицами. Допустим у вас есть таблица пользователей:

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

Создание таблицы orders

Давайте создадим таблицу orders, где user_id будет служить внешним ключом, ссылающимся на id в таблице 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

Поле user_id связано с полем id таблицы users, что позволяет создавать связи между пользователями и их заказами.

Выборка данных с JOIN

Посмотрим, как связаны данные в таблицах users и 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;

Результат:

user_id name order_id order_date
d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 Alice a1d3e15a-abc1-4b51-a320-2d4c859f7467 2024-10-20 12:34:56

Основные сценарии использования UUID

Идентификаторы пользователей и заказов: в распределённых системах, где данные могут поступать из разных источников.

Отметки для API: UUID часто используется в REST API для идентификации сущностей.

Глобальная синхронизация данных: например, когда данные собираются с разных серверов.

Типичные ошибки и особенности

Попытка генерировать UUID вручную: лучше использовать встроенные функции, такие как gen_random_uuid(), чтобы избежать ошибок.

Избыточное использование: не применяйте UUID там, где достаточно автоинкрементного INTEGER. Например, в локальных таблицах, которые никогда не будут масштабироваться.

Размер: UUID занимает больше места, что может повлиять на производительность запросов, особенно при индексировании.

2
Задача
SQL SELF, 16 уровень, 0 лекция
Недоступна
Генерация UUID
Генерация UUID
2
Задача
SQL SELF, 16 уровень, 0 лекция
Недоступна
Привязка UUID в связанных таблицах
Привязка UUID в связанных таблицах
Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Slevin Уровень 64
9 сентября 2025
Использование UUID в качестве внешнего ключа Результат показан неверно. Будет 4 строки, а не одна.
27 июня 2025
Установка расширения pgcrypto для использования функции gen_random_uuid() не обязательна. Данная функция уже идет под капотом в PostgreSQL. Если расширение установить без указания схемы, по умолчанию оно установиться в схему public, поэтому описанные ниже 2 способа идентичны

CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE EXTENSION pgcrypto SCHEMA "public" VERSION "1.3";
Получается что функция gen_random_uuid() после установки расширения будет располагаться сразу в 2 местах, в схеме "public" и в системной схеме "pg_catalog". Первичный поиск функций и иных элементов всегда начинается с системной схемы "pg_catalog", поэтому функция установленная с помощью расширения в схему "public" не будет даже использоваться. И при попытке установить расширение в схему "pg_catalog", нам выдаст ошибку - функция gen_random_uuid с такими параметрами уже есть

CREATE EXTENSION pgcrypto SCHEMA "pg_catalog";
-- ERROR: function "gen_random_uuid" already exists with same argument types