← Назад к вопросам

Можно ли упорядочивать UUID?

2.0 Middle🔥 171 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сортировка UUID: можно ли и нужно ли

Короткий ответ

Да, можно упорядочивать UUID, но результат зависит от версии UUID и использованного алгоритма. Однако это может быть неоптимальным для производительности БД.

Что такое UUID

UUID (Universally Unique Identifier) — это 128-битный идентификатор, представленный в виде 36 символов (с дефисами):
550e8400-e29b-41d4-a716-446655440000

Существует 5 версий UUID:

  • v1 — на основе MAC адреса и временной метки (сортируемый по времени)
  • v3 — на основе MD5 хеша имени
  • v4 — абсолютно случайный (НЕ сортируемый по смыслу)
  • v5 — на основе SHA-1 хеша имени
  • v6/v7 — новые версии с улучшенной сортируемостью (более современный подход)

Проблема: UUID v4 и производительность

Почему сортировка UUID v4 неоптимальна

UUID v4 генерируется случайно, поэтому при вставке новых строк:

INSERT INTO users (id, name) VALUES (550e8400-e29b-41d4-a716-446655440000, John);
INSERT INTO users (id, name) VALUES (a3b4c5d6-e7f8-4a1b-9c2d-3e4f5a6b7c8d, Jane);
INSERT INTO users (id, name) VALUES (12345678-1234-5678-1234-567812345678, Bob);

Эти UUID совершенно не связаны друг с другом по значению. B-tree индекс БД расфрагментируется:

Б-tree индекс:
├── 12345678...
├── 550e8400...
├── a3b4c5d6...
└── ...

Новые вставки требуют полной переиндексации, что вызывает:

  • Cache misses в памяти БД
  • Случайные обращения к диску (random I/O вместо sequential)
  • Деградацию производительности при большом количестве записей

Это особенно критично для таблиц с миллионами записей.

Решение 1: UUID v1 (временная сортировка)

550e8400-e29b-41d4-a716-446655440000
↑ первые биты это временная метка

UUID v1 включает временную метку, поэтому он монотонно возрастает со временем (примерно).

Плюсы:

  • Новые UUID естественно вставляются в конец B-tree
  • Лучше для индексирования
  • Как целые числа (incrementing ID)

Минусы:

  • Содержит MAC адрес хоста (security concern)
  • Не стандартизирован в более новых системах
  • Зависит от системного времени
import uuid
u = uuid.uuid1()
print(u)  # Пример: 550e8400-e29b-41d4-a716-446655440000

Решение 2: UUID v6/v7 (современный подход)

UUID v6 и v7 специально разработаны для монотонной сортировки:

v7: 550e8402-2033-7a18-957f-1a1847c17e2c
   ↑ первые биты это временная метка (сортируемая)

Плюсы:

  • Монотонно возрастающий (как SERIAL)
  • Сортируемый по времени
  • Хороший баланс между уникальностью и производительностью
  • Международный стандарт (RFC 4122bis)

Минусы:

  • Может быть недоступен в старых версиях БД
  • Требует специальной библиотеки для генерации
from uuid6 import uuid7
u = uuid7()
print(u)  # Monotonically increasing

Решение 3: ULID вместо UUID

ULID (Universally Unique Lexicographically Sortable Identifiers) — это альтернатива UUID, специально разработанная для сортировки:

01ARZ3NDEKTSV4RRFFQ69G5FAV (26 символов вместо 36)
↑ временная метка (сортируемая)

Плюсы:

  • Монотонно возрастающий по времени
  • Компактнее чем UUID (26 vs 36 символов)
  • Лучше читается человеком
  • Отлично для индексирования

Минусы:

  • Не является международным стандартом
  • Не везде поддерживается
from ulid import ULID
u = ULID()
print(u)  # 01ARZ3NDEKTSV4RRFFQ69G5FAV

Сравнение подходов

ПодходСортируемостьПроизводительностьСтандартИспользование
Serial (INT)✓ Отличная✓ Отличная✓ ДаLegacy системы
UUID v4✗ Нет✗ Плохая✓ ДаОбщие случаи (с оговоркой)
UUID v1✓ Хорошая✓ Хорошая✓ ДаLegacy, временные ID
UUID v6/v7✓ Отличная✓ Отличная✓ Да (новый)Современные системы
ULID✓ Отличная✓ Отличная✗ НетМикросервисы, высоконагруженные

Практические рекомендации

1. Для микросервисной архитектуры

Используйте UUID v7 или ULID:

from uuid6 import uuid7
user_id = uuid7()  # Монотонно возрастающий, хорош для индексирования

2. Для legacy проекта на PostgreSQL

Можно использовать встроенную функцию:

-- Современный подход
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Для сортировки добавьте индекс
CREATE INDEX idx_users_created_at ON users(created_at);

3. Если нужна максимальная производительность

Комбинируйте подходы:

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,      -- Быстрый локальный ID
    uuid UUID NOT NULL UNIQUE,      -- Уникальность в целой системе
    created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_users_uuid ON users(uuid);  -- Быстрый поиск по UUID

4. В NoSQL (MongoDB, DynamoDB)

Монотонно возрастающие ID критичнее:

// MongoDB: используйте ULID или UUID v7
const user = {
    _id: generateULID(),  // Монотонно возрастающий
    name: John
};

Выводы

  1. UUID v4 можно сортировать, но это не имеет логического смысла
  2. Для оптимальной производительности используйте UUID v7 или ULID — они монотонно возрастают
  3. Не используйте случайные UUID как первичный индекс в высоконагруженных системах — это приведёт к фрагментации B-tree
  4. Комбинируйте ID и UUID — локальный SERIAL для первичного ключа, UUID для глобальной уникальности