UUID v4: полное руководство по универсальным уникальным идентификаторам
UUID (Universally Unique Identifier) — это стандарт идентификаторов, который позволяет генерировать уникальные значения без центрального координатора. Спецификация описана в RFC 4122 и широко применяется в распределённых системах, базах данных, API и файловых системах. В этой статье разберём формат UUID, его версии, практическое применение и генерацию в популярных языках и базах данных.
Что такое UUID
UUID (также известный как GUID — Globally Unique Identifier в экосистеме Microsoft) — это 128-битный идентификатор, представленный в виде 32 шестнадцатеричных символов, разделённых дефисами.
Формат 8-4-4-4-12
Стандартный формат UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, где каждая группа соответствует определённому количеству символов:
- 8 символов — первые 32 бита (time_low)
- 4 символа — следующие 16 бит (time_mid)
- 4 символа — версия и 12 бит (time_hi_and_version)
- 4 символа — вариант и 12 бит (clock_seq_and_reserved, clock_seq_low)
- 12 символов — 48 бит (node)
Пример: 550e8400-e29b-41d4-a716-446655440000
Строковое представление занимает 36 символов (32 hex + 4 дефиса). В бинарном виде UUID занимает ровно 16 байт, что важно учитывать при проектировании схемы базы данных.
Версии UUID
Спецификация RFC 4122 определяет несколько версий UUID, различающихся способом генерации.
UUID v1 — на основе времени
UUID v1 использует MAC-адрес сетевой карты и временную метку (100-наносекундные интервалы с 15 октября 1582 года). Идентификаторы лексикографически сортируемы по времени создания, что удобно для индексации. Недостаток — раскрытие MAC-адреса создаёт риски для конфиденциальности, поэтому v1 редко используется в публичных API.
UUID v4 — случайный
UUID v4 — наиболее распространённая версия в веб-разработке. 122 бита из 128 генерируются криптографически стойким генератором случайных чисел (CSPRNG), 6 бит зарезервированы под версию (0100 в позиции 13) и вариант (10 в позиции 17). Идеален для большинства сценариев, когда не требуется сортировка по времени. Поддержка встроена во все современные языки и базы данных.
UUID v5 — на основе namespace и имени
UUID v5 генерируется детерминированно через SHA-1 хеш от namespace UUID и имени. Одинаковые входные данные всегда дают один и тот же UUID. Полезен для создания идентификаторов из имён (например, имён доменов или ресурсов). Стандартные namespace: DNS (6ba7b810-9dad-11d1-80b4-00c04fd430c8), URL (6ba7b811-9dad-11d1-80b4-00c04fd430c8). UUID v4 и v5 — самые распространённые в веб-разработке.
UUID v7 — время + случайность (новый стандарт)
UUID v7 — относительно новый вариант (RFC draft), комбинирующий временную метку и случайные биты. Идентификаторы сортируемы по времени, как v1, но без раскрытия MAC-адреса. Рекомендуется для новых проектов, где важна сортировка.
UUID v4 в деталях
В UUID v4 случайными являются 122 бита. Версия (4) кодируется в позиции 13-го символа, вариант — в 17-м.
Вероятность коллизии
При 122 случайных битах пространство значений составляет 2^122 ≈ 5,3×10^36. По формуле вероятности коллизии (парадокс дней рождения): для достижения 50% вероятности коллизии потребуется сгенерировать около 2,7×10^18 UUID. Для сравнения: генерация миллиарда UUID в секунду потребовала бы 85 лет для достижения этого порога. На практике коллизии UUID v4 считаются невозможными при разумном объёме генерации — важнее обеспечить использование криптографически стойкого ГПСЧ в выбранной библиотеке.
UUID vs автоинкремент
Выбор между UUID и автоинкрементным целым числом зависит от архитектуры системы.
Преимущества UUID
- Распределённые системы — генерация без обращения к базе данных, несколько узлов могут создавать записи независимо
- Объединение баз — при слиянии данных из разных источников конфликты ID исключены
- Безопасность — сложнее угадать следующий ID, что снижает риски перебора в API
- Клиентская генерация — ID можно создать на клиенте до отправки на сервер (offline-first)
Недостатки UUID
- Размер — 16 байт против 4–8 байт для integer
- Производительность индексов — случайные значения ухудшают эффективность B-tree индексов из-за фрагментации
- Читаемость — длинная строка неудобна для отладки и логов
- Сортировка — UUID v4 не сортируемы по времени создания
Когда выбирать UUID
Используйте UUID, если: микросервисная архитектура, репликация между дата-центрами, мультитенантность с изоляцией данных, публичные API с чувствительными ID, offline-first приложения с синхронизацией. Используйте автоинкремент, если: монолитная архитектура, очень высокая нагрузка на запись (десятки тысяч вставок в секунду), критична производительность индексов, требуется компактное хранение. Гибридный подход: UUID для внешнего API и межсервисного обмена, внутренний integer для связей между таблицами в рамках одной базы — даёт баланс между удобством и производительностью.
Генерация UUID
JavaScript
В современных браузерах и Node.js 19+ доступен crypto.randomUUID():
// Браузер и Node.js 19+
const id = crypto.randomUUID();
console.log(id); // "550e8400-e29b-41d4-a716-446655440000"
Для Node.js до 19 версии используйте пакет uuid:
const { v4: uuidv4 } = require('uuid');
const id = uuidv4();
Python
Стандартная библиотека uuid:
import uuid
id = uuid.uuid4()
print(id) # 550e8400-e29b-41d4-a716-446655440000
print(str(id)) # строковое представление
PostgreSQL
Встроенная функция gen_random_uuid() (требует расширение pgcrypto в старых версиях; в PostgreSQL 13+ встроена):
SELECT gen_random_uuid();
-- a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
MySQL
SELECT UUID();
-- или MySQL 8.0.13+:
SELECT UUID_TO_BIN(UUID());
Другие языки
В Go: пакет github.com/google/uuid, функция uuid.New(). В Java: java.util.UUID.randomUUID(). В C#: Guid.NewGuid(). В Ruby: require 'securerandom' и SecureRandom.uuid. Все эти реализации соответствуют RFC 4122 и генерируют криптографически стойкие случайные значения для v4.
UUID в базах данных
Хранение: BINARY(16) vs CHAR(36)
Рекомендуется хранить UUID в бинарном формате:
| Тип | Размер | Индексация |
|---|---|---|
| CHAR(36) | 36 байт | Медленнее |
| BINARY(16) | 16 байт | Эффективнее |
В PostgreSQL используйте тип uuid — он оптимизирован, занимает 16 байт и поддерживает валидацию формата на уровне типа. В MySQL до версии 8.0 нет нативного типа UUID, поэтому BINARY(16) с функциями UUID_TO_BIN и BIN_TO_UUID — рекомендуемый подход:
CREATE TABLE users (
id BINARY(16) PRIMARY KEY,
email VARCHAR(255)
);
-- Вставка
INSERT INTO users (id, email) VALUES (UUID_TO_BIN(UUID()), 'user@example.com');
Индексация
Случайные UUID создают «горячие» точки в B-tree индексах — новые страницы вставляются в случайные места, что увеличивает количество split операций и фрагментацию. Варианты оптимизации:
- UUID v7 — сортируемость по времени уменьшает фрагментацию, новые записи попадают в конец индекса
- Переупорядочивание байтов — хранить time_low в начале UUID (если используется v1), улучшает локальность при вставках
- Партиционирование — по префиксу UUID для распределения нагрузки между партициями
- Составные ключи — (tenant_id, uuid) для мультитенантных систем, улучшает изоляцию и кэширование
При выборе первичного ключа учитывайте, что в PostgreSQL и MySQL кластеризованные индексы (primary key) определяют физический порядок данных на диске. Случайный UUID приводит к случайному распределению строк, что может снизить эффективность последовательного чтения.
UUID в API и URL
UUID хорошо подходят для публичных идентификаторов в REST API:
GET /api/users/550e8400-e29b-41d4-a716-446655440000
Преимущества: нельзя перебрать соседние ID (в отличие от /users/1, /users/2), стабильность при слиянии систем, отсутствие информации о количестве записей. Недостаток — длинные URL (36 символов). Для коротких ссылок рассмотрите base62-кодирование (22 символа) или отдельные короткие идентификаторы (nanoid, ulid). В заголовках и cookie UUID обычно передают без дефисов для экономии места.
Типичные паттерны использования
UUID как первичный ключ
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
total DECIMAL(10,2)
);
UUID как API-токен
Для токенов доступа UUID v4 подходит: 122 бита энтропии обеспечивают достаточную стойкость против перебора. Однако для высоконагруженных систем и токенов с длительным сроком жизни предпочтительнее криптографически стойкие случайные строки (например, 256 бит, закодированные в base64url) — больше энтропии при сопоставимой длине. UUID удобен для одноразовых кодов подтверждения, ссылок для сброса пароля, идентификаторов сессий.
UUID в именах файлов
Использование UUID в именах файлов исключает коллизии при загрузке:
uploads/550e8400-e29b-41d4-a716-446655440000.pdf
Производительность
Ключевые моменты при работе с UUID в production:
- Размер индекса — UUID увеличивает размер индексов в 2–4 раза по сравнению с BIGINT (8 байт). На таблице с 10 млн записей разница может составлять сотни мегабайт
- Сравнение — бинарное сравнение 16 байт быстрее строкового 36 символов. Всегда используйте нативный тип UUID или BINARY(16), не VARCHAR/CHAR
- Фрагментация — при высокой частоте вставок индексы на UUID v4 фрагментируются сильнее, чем на последовательные значения. Периодический REINDEX (PostgreSQL) или OPTIMIZE TABLE (MySQL) может потребоваться чаще
- Кэширование — случайные UUID хуже используют кэш страниц БД, так как обращения распределены по всему индексу
- Бенчмарки — на тестах вставки UUID обычно дают 10–30% просадку по сравнению с автоинкрементом; для большинства приложений (до тысяч вставок в секунду) это приемлемо. Чтение по первичному ключу практически не страдает
Частые ошибки при работе с UUID
Избегайте хранения UUID как строки в неправильном формате: некоторые ORM по умолчанию используют VARCHAR(36), что неоптимально. Проверяйте регистр при сравнении — стандарт требует lowercase, но не все библиотеки это гарантируют. Не используйте UUID v1 в публичных системах из-за утечки MAC-адреса. При миграции с integer на UUID планируйте обновление внешних ключей и индексов — операция может занять значительное время на больших таблицах.
Заключение
UUID v4 — надёжный выбор для распределённых систем, API и сценариев, где важна независимая генерация идентификаторов. Понимание формата 8-4-4-4-12, различий между версиями и компромиссов по производительности помогает принять обоснованное решение между UUID и автоинкрементом. Для новых проектов с требованием сортировки по времени создания рассмотрите UUID v7.
Для быстрой генерации UUID в браузере воспользуйтесь онлайн-генератором UUID.