Что такое UUID в SQL
Хранить UUID текстом — самая распространённая дорогая ошибка. В PostgreSQL есть родной тип uuid ровно на 16 байт; в MySQL 8 можно взять BINARY(16) с UUID_TO_BIN(); в SQL Server — uniqueidentifier. Все три компактнее и быстрее в сравнении, чем строка из 36 символов, и все три проверяют значение при записи.
Выбор версии в базе важнее, чем где-либо ещё, — из-за индекса. Случайные значения v4 разбрасываются по B-дереву, и каждая вставка затрагивает новую страницу; упорядоченный по времени v7 держит новые строки рядом, и вставки остаются дешёвыми. Именно поэтому в PostgreSQL 18 появилась функция uuidv7(); на более старых версиях и в других СУБД v7 создаётся в приложении и передаётся как параметр.
Как использовать
- Выберите функцию для своей СУБД:
uuidv7(),gen_random_uuid(),UUID()илиNEWID(). - Назначьте её значением по умолчанию, чтобы вставки не указывали значение вручную.
- Храните в родном типе (16 байт), а не в тексте, и используйте v7, если столбец индексируется.
Сценарии
- Первичные ключи, которые создаются без обращения к базе, например в распределённом сервисе.
- Идемпотентный импорт: детерминированный v5 из исходной строки защищает от дублей при повторном запуске.
- Публичные идентификаторы, которые не должны раскрывать число строк, в отличие от автоинкремента.
Сравнение UUID в SQL с другими форматами
| Вариант | Когда использовать |
|---|---|
PostgreSQL uuid | Родной тип на 16 байт с проверкой при записи; <code>uuidv7()</code> с версии 18. |
MySQL BINARY(16) | Компактно, но требует <code>UUID_TO_BIN(uuid, 1)</code>, чтобы переставить время для локальности индекса. |
SQL Server uniqueidentifier | Родной тип; <code>NEWID()</code> — это v4, <code>NEWSEQUENTIALID()</code> — упорядочен. |
Текстовый столбец | 36 символов, без проверки, медленнее сравнение — избегайте, если в СУБД есть родной тип. |
Примеры кода
PostgreSQL
-- Случайный v4 (pgcrypto или встроено с PostgreSQL 13)
SELECT gen_random_uuid();
-- Упорядоченный v7 (PostgreSQL 18+)
SELECT uuidv7();
-- Значение по умолчанию и запросы метаданных
CREATE TABLE events (
id uuid PRIMARY KEY DEFAULT uuidv7(),
created_at timestamptz NOT NULL DEFAULT now()
);
SELECT uuid_extract_version(id), uuid_extract_timestamp(id) FROM events;
MySQL
SELECT UUID(); -- v1, основан на времени
SELECT UUID_TO_BIN(UUID(), 1); -- байты v1 со временем вперёд: удобно индексу
CREATE TABLE events (
id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID(), 1)),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
SELECT BIN_TO_UUID(id, 1) FROM events; -- обратно в текст
SQL Server
SELECT NEWID(); -- v4, случайный
SELECT NEWSEQUENTIALID(); -- упорядоченный, но только как значение по умолчанию
CREATE TABLE events (
id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID(),
created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),
CONSTRAINT pk_events PRIMARY KEY CLUSTERED (id)
);
Детерминированные ключи
-- PostgreSQL: стабильный id из естественного ключа
SELECT md5('tenant:42')::uuid;
-- Надёжнее: пространство имён вместо произвольного хэша
SELECT uuid_generate_v5(uuid_ns_url(), 'https://example.com/tenant/42');
Частые вопросы
Что лучше как первичный ключ: UUID или автоинкремент?
Целое число — если таблица локальная, небольшая и вы никогда не объединяете данные из нескольких баз: оно компактнее и не требует координации. UUID — когда идентификаторы должны создавать несколько сервисов, когда строки импортируются извне или когда ключ публичен и не должен раскрывать число строк и их порядок.
Почему вставка UUID медленнее вставки целого числа?
Почти всегда из-за локальности индекса. Случайные ключи v4 вызывают разбиение страниц по всему B-дереву. Переведите столбец на упорядоченный по времени v7 (или NEWSEQUENTIALID(), или UUID_TO_BIN(uuid, 1) в MySQL) — и вставки снова станут почти последовательными.
Можно ли создавать UUID в базе и при этом сохранить переносимость?
Да: создавайте значение в приложении и передавайте параметром. Тогда база только хранит и проверяет его, один и тот же код работает на PostgreSQL, MySQL и SQL Server, а идентификатор известен ещё до INSERT — именно это упрощает идемпотентные повторы.