UUID · ULID · Базы данных

UUID v4 или ULID: что выбрать для ID в базе данных

UUID v4 — стандарт де-факто, но у него есть проблема: случайность бьёт по производительности индексов при большом объёме данных. Разбираем UUID v4, v7 и ULID — когда что использовать.

Генератор UUID / ULID →

Краткое сравнение: UUID v4 vs ULID vs UUID v7

ХарактеристикаUUID v4ULIDUUID v7
Размер128 бит (36 символов)128 бит (26 символов)128 бит (36 символов)
Формат8-4-4-4-12 hexBase32 Crockford8-4-4-4-12 hex
Пример550e8400-e29b-41d4-a716-44665544000001ARZ3NDEKTSV4RRFFQ69G5FAV018c6d5e-1234-7abc-8def-012345678901
Временная метка❌ Нет✅ Первые 48 бит (мс)✅ Первые 48 бит (мс)
Сортируемость❌ Случайный✅ Монотонный✅ Монотонный
RFC стандарт✅ RFC 4122❌ Нет RFC✅ RFC 9562 (2024)
Совместимость✅ Везде⚠️ Требует конвертации✅ Везде (UUID-совместим)
Производительность индексов❌ Плохая при >1M записей✅ Хорошая✅ Хорошая

Почему UUID v4 плох для первичного ключа при большом объёме

UUID v4 генерируется полностью случайно — 122 бита случайных данных. Это значит каждый новый UUID попадает в случайную позицию в B-tree индексе базы данных.

Последствия при большом объёме данных:

На практике: при <100k записей разница незаметна. При 1M+ записей UUID v4 vs ULID на вставке даёт заметную разницу в скорости. При 10M+ — принципиальная.

Как работает ULID

ULID (Universally Unique Lexicographically Sortable Identifier) состоит из двух частей:

01ARZ3NDEK TSV4RRFFQ69G5FAV ^─────────^ ^───────────────^ 48 бит 80 бит timestamp случайность (мс от эпохи) (криптографическая)

UUID v7 — современный стандарт (RFC 9562, 2024)

UUID v7 — официальный RFC-стандарт, принятый в 2024 году. По структуре похож на ULID, но сохраняет UUID-формат:

018c6d5e-1234-7abc-8def-012345678901 ^────────────^ ^ ^ 48 бит ts 7 variant (мс эпоха) ver

Преимущества UUID v7 перед ULID:

Поддержка в базах данных

PostgreSQL

-- UUID v4 (стандарт) CREATE EXTENSION IF NOT EXISTS "pgcrypto"; INSERT INTO users (id) VALUES (gen_random_uuid()); -- UUID v7 (PostgreSQL 17+ или через функцию) -- Пример функции для UUID v7: CREATE OR REPLACE FUNCTION uuid_generate_v7() RETURNS uuid AS $$ SELECT encode( set_bit( set_bit( overlay(uuid_send(gen_random_uuid()) placing substring(int8send(floor(extract(epoch from clock_timestamp()) * 1000)::bigint) from 3) from 1 for 6), 52, 1), 53, 1), 'hex')::uuid; $$ LANGUAGE sql VOLATILE;

MySQL / MariaDB

-- UUID как BINARY(16) — эффективнее VARCHAR(36) CREATE TABLE users ( id BINARY(16) DEFAULT (UUID_TO_BIN(UUID(), 1)) PRIMARY KEY, name VARCHAR(255) ); -- Чтение обратно SELECT BIN_TO_UUID(id, 1) as id, name FROM users;

SQLite

-- SQLite не имеет UUID типа — используем TEXT или BLOB CREATE TABLE users ( id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-4' || substr(lower(hex(randomblob(2))),2) || '-' || substr('89ab',abs(random()) % 4 + 1, 1) || substr(lower(hex(randomblob(2))),2) || '-' || lower(hex(randomblob(6)))) );

Рекомендации по выбору

СитуацияРекомендацияПочему
Новый проект, PostgreSQLUUID v7 или ULIDЛучшая производительность индексов с первого дня
Существующая система с UUID v4Оставить UUID v4Миграция рискованна, выгода оправдана только при реальных проблемах с производительностью
Микросервисы, несколько БДUUID v7Стандарт RFC, совместим со всеми системами
API — ID в URLULID26 символов без дефисов, URL-безопасный
Нужна временная метка в IDULID или UUID v7Первые биты = timestamp, можно извлечь время создания
Публичный API, максимальная совместимостьUUID v4Все клиенты понимают UUID, нет путаницы
Совет 2026: для новых проектов выбирайте UUID v7 — это официальный стандарт с хорошей производительностью и полной обратной совместимостью с UUID v4 в плане схемы данных.

Вероятность коллизий

Все три формата на практике свободны от коллизий:

Сгенерировать UUID / ULID / UUID v7 →

Часто задаваемые вопросы

Что лучше для первичного ключа в PostgreSQL: UUID или ULID?

Для PostgreSQL ULID (или UUID v7) заметно лучше чем UUID v4 в качестве первичного ключа при больших объёмах. UUID v4 полностью случайный — из-за этого B-tree индексы фрагментируются при вставке. ULID и UUID v7 монотонно возрастают по времени, новые записи попадают в конец индекса — меньше разбиений страниц, лучше производительность.

Чем UUID v7 отличается от ULID?

UUID v7 — стандарт RFC 9562 (2024), 128 бит, формат совместим с обычными UUID (hex с дефисами). ULID — 128 бит, Base32 кодировка (26 символов), нет официального RFC. UUID v7 предпочтительнее если нужна совместимость с системами ожидающими UUID-формат. ULID лучше читается человеком и компактнее в URL.

Можно ли использовать UUID как текстовое поле в MySQL?

Технически можно, но это плохая практика: UUID в VARCHAR(36) занимает 36 байт против 16 байт в BINARY(16). Разница в размере индекса значительна при миллионах записей. В MySQL 8+ используйте UUID_TO_BIN() / BIN_TO_UUID() для эффективного хранения UUID.