Начиная с первых курсов университета, первой ассоциацией у студентов ИТ специальностей со словом «ключ» в базах данных является идентификатор. В принципе это верно, однако следует это понятие расширить – связать его с целостностью данных и производительностью. Рассмотрим эволюцию подходов к работе с ключами на примере роста выдуманной компании NeoCat.

Логический уровень: ключи как идентификаторы
Котята часто делают переводы. Поэтому возникла необходимость чтобы кто-то вел их учет. Именно этим и занимается компания NeoCat. Она начинала как скромный стартап. На начальном этапе разработчики рассматривали ключи исключительно как инструменты обеспечения уникальности и непротиворечивости информации. Команда состояла всего из трех разработчиков, которые предпочитали простые и понятные решения, максимально отражающие бизнес-процессы компании. Целевой таблицей стартапа является таблица payments. Бизнес-процесс был изначально устроен так, что по одному клиенту мог проводиться только один платеж в день.
CREATE TABLE payments (
-- Неуникальное поле, у одного клиента может быть несколько платежей
client_name VARCHAR(20) NOT NULL,
-- Номер платежа формируется как {МЕСЯЦ}-{НОМЕР_В_МЕСЯЦЕ}, например, 03-005. Нумерация начинается заново каждый месяц.
payment_number VARCHAR(6) NOT NULL,
-- Дата совершения платежа
payment_date DATE NOT NULL,
-- Сумма платежа
amount DECIMAL(10,2)
);
На этом этапе команда NeoCat неосознанно столкнулась с палитрой концепций ключей. Набор атрибутов, который позволяет обеспечить уникальную идентификацию, называется кандидатским (потенциальным) ключом, то есть он является кандидатом на то, чтобы быть первичным ключом. В момент становления одного ключа первичным, все остальные кандидатские ключи становятся альтернативными ключами. Наконец, суперключ - это такой набор атрибутов таблицы, по которому каждая запись однозначно идентифицируется, даже если часть атрибутов в этом наборе не является необходимой.
В нашем случае рассматривая различные варианты идентификации записей, они обнаружили суперключи, это комбинации вроде (client_name, payment_number, payment_date, amount) или даже (client_name, payment_number, payment_date) - все они гарантировали уникальность, но содержали явно избыточные поля.
Кандидатские ключи:
(client_name, payment_date) - наиболее логичная комбинация, отражающая бизнес-процесс
(client_name, payment_number, EXTRACT(YEAR FROM payment_date)) - потенциальный ключ теоретически возможный, но громоздкий составной ключ.
После выбора первичного ключа, оставшийся кандидат стал альтернативным ключом. Котики-разработчики изменили сущность payments, чтобы она отразила выбранный ими подход.
CREATE TABLE payments (
client_name VARCHAR(20) NOT NULL,
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
PRIMARY KEY (client_name, payment_date)
);
Выбор естественного составного ключа, который имеет понятный бизнес-смысл казался идеальным решением. Сотрудники сразу понимали, что идентификатор платежа состоит из наименования клиента и даты. Не требовалось создавать искусственные идентификаторы, что упрощало начальную разработку.
Но даже на этом первом этапе выбора первичного ключа есть нюансы: в классической реляционной модели первичный ключ действительно формально объединяет ограничения UNIQUE и NOT NULL, но в реальности современных СУБД такое уравнение работает лишь как удобное упрощение. Ключевая роль PK — быть структурным якорем и декларацией основного принципа организации данных, и эта роль может реализовываться по-разному: в ClickHouse PK определяет лишь порядок сортировки и партиционирования, допуская дубликаты; в Cassandra — распределение данных по узлам; а некоторые SQL-СУБД в определённых условиях тоже допускают NULL в PK. Таким образом, уникальность и запрет NULL — это распространённые, но не универсальные технические средства для реализации более глубокой архитектурной функции ключа как главного идентификатора сущности. Более того, сама необходимость уникальности не всегда очевидна. Можно ли представить таблицу без единого ключа? Технически — да, но такая таблица быстро превратится в хранилище противоречивых и неуправляемых дубликатов. Таким образом, ключ — это не просто «клей», связывающий таблицы, а архитектурный инструмент, который навязывает данным внутреннюю логику и структуру, реализуя реляционную модель.
Очень скоро у NeoCat проявились фундаментальные проблемы. Бизнес-правила изменились: оказалось, что одному клиенту можно переводить несколько платежей в день. Это простое изменение полностью разрушило уникальность выбранного первичного ключа. Простое на первый взгляд решение оказалось хрупким и негибким перед лицом меняющихся бизнес-требований. Этот первый этап стал для NeoCat ценным уроком: естественные ключи, несмотря на свою понятность, могут стать источником проблем при масштабировании бизнеса и изменении правил. Команда осознала, что стабильность и гибкость часто важнее первоначальной простоты.
Столкнувшись с ограничениями естественных ключей, NeoCat начала экспериментировать с различными подходами. Первой попыткой стали вычисляемые ключи, они искусственно сформированы из бизнес-атрибутов, и их значения понятны человеку. Классический пример - конкатенированные ключи, где несколько полей объединяются в одну строку:
CREATE TABLE payments (
client_name VARCHAR(20) NOT NULL,
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
payment_code VARCHAR(100) GENERATED ALWAYS AS
(client_name || '_' || payment_date || '_' || LPAD(payment_number::text, 3, '0')) STORED,
PRIMARY KEY (payment_code)
);
Вычисляемый ключ payment_code решает проблему уникальности, но порождает новые сложности — громоздкие индексы и проблемы с производительностью при частых обновлениях базовых полей, от которых зависел вычисляемый ключ. Более того, при построении связей с другими таблицами разработчики столкнулись с необходимостью сложных проверок, что усложняло JOIN-операции и снижало производительность запросов.

Уровень ограничений: ключи как инструменты бизнес-логики
С ростом бизнеса и усложнением процессов NeoCat столкнулась с необходимостью реализации сложных валидаций и специализированных ключей для конкретных сценариев. Компания расширяла свою функциональность, добавляя внешние ключи для обеспечения ссылочной целостности:
CREATE TABLE payments (
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
client_id BIGINT NOT NULL,
payment_code VARCHAR(50) GENERATED ALWAYS AS
(client_id || '_' || payment_date || '_' || LPAD(payment_number::text, 3, '0')) STORED,
PRIMARY KEY (payment_code)
FOREIGN KEY (client_id) REFERENCES clients(client_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
Внешние ключи — это не инструмент для идентификации записей, они гарантируют целостность данных, автоматически предотвращая появление некорректных ссылок между таблицами. Они позволяют декларативно описывать бизнес‑правила на уровне схемы БД, упрощая логику приложения за счет автоматизации каскадных операций. Это переносит проверки целостности с прикладного уровня на уровень СУБД, повышая надежность системы. Конфигурация вроде ON UPDATE CASCADE обеспечивает автоматическое распространение изменений на всех связанных таблицах, что значительно упрощает операции обновления данных и поддерживает согласованность информации во всей системе. ON DELETE RESTRICT предотвращает удаление записей, на которые существуют ссылки или установки NULL. Как и другие настройки они мощны, но требуют осторожности.
Ключевой недостаток внешних ключей - снижение производительности при массовых операциях из-за дополнительных проверок. В высоконагруженных OLTP-системах без дополнительных настроек они могут создавать каскадные блокировки, приводя к конфликтам и снижению параллелизма. Поддержка внешних ключей усложняет миграции схемы и ограничена во многих распределенных и аналитических БД. Кроме того, они иногда маскируют проблемы дизайна схемы, когда вместо нормализации добавляются избыточные связи.
Также были созданы дедупликационные ключи для контроля качества данных в той самой таблице clients, на которую ссылалась наша исходная таблица:
CREATE TABLE clients (
client_id BIGINT PRIMARY KEY,
email VARCHAR(100),
phone VARCHAR(20),
tax_id VARCHAR(30),
-- дедупликационный ключ
UNIQUE(email, phone, tax_id)
);
Дедупликационные ключи — это наборы атрибутов, по которым определяется дубликат записи, они допускают NULL‑значения и служат именно для бизнес‑логики контроля качества. Такой подход позволял находить потенциальные дубликаты клиентов без жестких ограничений на обязательность заполнения всех полей. На практике это означало, что система могла идентифицировать дубликаты даже при частично заполненной информации, что было особенно важно в сценариях постепенного сбора данных о клиентах. Отметим, что в нашем примере UNIQUE ограничение служит примером попытки контролировать дубликаты, но в реальных системах дедупликация часто требует более сложной, вероятностной или процедурной логики.
Физический уровень: суррогатные ключи и производительность
По мере роста объема данных и увеличения нагрузки NeoCat столкнулась с серьезными проблемами производительности, особенно в JOIN-операциях. Необходимость стабильных идентификаторов, не зависящих от изменений бизнес-логики, привела к переходу на суррогатные ключи - искусственные идентификаторы, генерируемые системой исключительно для целей связи таблиц.
Команда NeoCat реализовала генерацию идентификаторов, начиная с максимального номера платежа в системе, используя последовательности.
-- Специальная последовательность с шагом 1, начинающаяся с 100
CREATE SEQUENCE payment_id_seq
START WITH 100
INCREMENT BY 1;
CREATE TABLE payments (
payment_id BIGINT PRIMARY KEY DEFAULT nextval('payment_id_seq'),
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
client_id BIGINT NOT NULL,
FOREIGN KEY (client_id) REFERENCES clients(client_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
Однако они столкнулись с проблемой: последовательности использовались без кэширования, что оказалось дорогим удовольствием для производительности. Простое добавление кэша увеличило производительность в десятки раз.
CREATE SEQUENCE payment_id_seq
START WITH 100
INCREMENT BY 1
CASHE 100;
Есть нюанс: использование кэша повышает производительность, но ценой потери строгой последовательности. При сбое или перезагрузке БД все кэшированные, но не использованные значения теряются, образуя «дырки» в нумерации. Также каждый SEQUENCE требует места в системном каталоге. Следовательно, если требуется гарантированная непрерывность последовательности ключей — что критично для аудита, борьбы с мошенничеством или соблюдения таких норм, как законы о кассовых аппаратах, — кэшированное решение не подходит.
Переход на суррогатные ключи показал значительное улучшение производительности: операции соединения таблиц ускорились в несколько раз благодаря более эффективному сравнению целочисленных значений вместо строковых. Но в связи с вышеперечисленными минусами решено было перейти на классический автоинкремент:
CREATE TABLE payments (
payment_id BIGSERIAL PRIMARY KEY,
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
client_id BIGINT NOT NULL,
FOREIGN KEY (client_id) REFERENCES clients(client_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
Использование BIGSERIAL предоставило команде NeoCat автоматическое управление последовательностью, что упростило разработку и снизило вероятность ошибок. Использование дискового пространства для индексов сократилось, так как последовательные ID лучше упаковывались в страницы данных. Разработчики осознали, что эксперимент с ручным SEQUENCE не принес дополнительной пользы бизнесу. Бизнес-пользователи не заметили разницы в формате ID, но ощутили улучшение производительности системы.

Распределенный уровень: UUID и глобальная уникальность
Экспоненциальный рост бизнеса NeoCat потребовал перехода к распределенной системе баз данных. Это привело к внедрению UUID (Universally Unique Identifier). Ключевым преимуществом UUID стала независимо и гарантировано уникальная генерация идентификаторов в любой точке системы без централизованной координации, что критически важно для горизонтального масштабирования и отказоустойчивости. Глобальная уникальность упростила слияние данных из разных источников и предоставила гибкость — например, генерацию ID на стороне клиента до сохранения, что улучшило отзывчивость интерфейсов и работу в офлайн-режимах.
CREATE TABLE payments (
-- gen_random_uuid() генерирует UUID версии 4 для PostgreSQL 13+
payment_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
client_id BIGINT NOT NULL,
FOREIGN KEY (client_id) REFERENCES clients(client_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
Изначальный выбор UUID v4 был обусловлен его идеальной уникальностью и безопасностью благодаря случайному характеру генерации. Однако на практике команда NeoCat столкнулась с серьезными проблемами производительности. Случайный характер UUID v4 приводил к сильной фрагментации индексов, что значительно снижало производительность операций вставки и чтения. Каждая новая запись с высокой вероятностью попадала на разные страницы индекса, вызывая большое количество операций ввода-вывода. Решением стал переход к UUIDv7 с временной сортировкой:
CREATE TABLE payments (
-- это функция из расширения uuid-ossp
payment_id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
client_id BIGINT NOT NULL,
FOREIGN KEY (client_id) REFERENCES clients(client_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
Переход на UUID v7 стал ключевым архитектурным решением для NeoCat. Временная компонента в UUID v7 обеспечивает естественное упорядочивание записей, что значительно уменьшает фрагментацию данных. Новые записи добавляются последовательно в конец индексов, что снижает количество операций разделения страниц и улучшает общую производительность системы. При этом сохраняется глобальная уникальность идентификаторов, необходимая для распределенной архитектуры. Наши котята отметили, что данный ключ хорошо подходит для независимой загрузки данных из разных источников.
Основными минусами UUID v7 остаются его большой размер (16 байт против 4-8 у целочисленных ключей), что увеличивает объем индексов и снижает эффективность хранения, а также повышенная сложность реализации, требующая поддержки со стороны библиотек и фреймворков. Упорядоченность на основе времени, являясь преимуществом для производительности, одновременно раскрывает информацию о моменте создания объекта и требует синхронизации системных часов между инстансами для сохранения корректной последовательности. Кроме того, его структура менее случайна по сравнению с UUID v4, что может быть недостатком в сценариях, где критична полная непредсказуемость идентификаторов, например, если он используется для контроля доступа
Несмотря на долгую эволюцию и разнообразие форматов — таких как UUID, GUID, ULID, OID или CUID — каждый из которых часто привязан к конкретному технологическому стеку, в современной практике доминирующим и наиболее универсальным подходом к генерации распределённых идентификаторов остаются варианты UUID/GUID, адаптированные под различные сценарии использования.
Data Warehouse уровень: хеш-ключи и идемпотентность
В компании объем данных начал измеряться в петабайтах. Все чаще и чаще идут разговоры об эффективности потоков данных и идемпотентности данных. Кроме того, аналитики хотели бы тоже рост эффективности в выполнении запросов. Разработчики пришли к общему консенсусу - надо переходить на детерминированные хэши. Они хороши тем, что одни и те же входные данные, переданные в одну и ту же хеш-функцию, всегда дают абсолютно одинаковый результат. В нашем случае хэш-ключ будет искусственно вычисляться на основе бизнес-ключа. Это частный случай естественных ключей, атрибут или набор атрибутов, которые уже используются в бизнес-процессах для однозначной идентификации объекта.
Пример на SQL (используем sha256, можно рассматривать MD5)
CREATE TABLE payments (
-- первичный ключ - детерминированный хэш
payment_hash BYTEA PRIMARY KEY DEFAULT sha256(
( payment_number ||
'|' || payment_date::TEXT ||
'|' || client_id::TEXT
)::bytea
),
-- Бизнес-атрибуты
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
amount DECIMAL(10,2),
client_id BIGINT NOT NULL,
-- Внешний ключ
FOREIGN KEY (client_id) REFERENCES clients(client_id)
ON DELETE RESTRICT
ON UPDATE CASCADE,
-- Бизнес-ограничения
UNIQUE(payment_number, payment_date, client_id)
);
За счет того, что JOIN по хешу чаще всего выполняется быстрее, вырастет и производительность сложных запросов. Часто упоминают такой недостаток, как теоретическая вероятность коллизии, но для современных алгоритмов, таких как SHA-256, она стремится к минимуму (например, для 50% шанса её найти потребуется сгенерировать порядка 2^128 хешей, что выходит далеко за пределы возможностей современных вычислительных систем), поэтому на практике этим риском пренебрегают. Однако, если требования к системе предполагают абсолютную, а не вероятностную уникальность, её можно гарантировать, проверяя при вставке наличие уже существующей записи с таким же хешем. Это обеспечит уникальность ценой производительности, так как каждая операция вставки будет сопровождаться дополнительным поиском. Нужно также учитывать необходимость явной обработки NULL-значений, так как стандартное хеширование NULL в разных системах может давать разные результаты, что нарушает детерминизм. Однако архитектор должен знать о самом факте ее существования, особенно в системах с экстремально большим объемом данных или высокими требованиями к безопасности. Требует дополнительного шага в потоках данных для расчета хеша перед вставкой
Enterprise-уровень: гибридная архитектура и комплексное решение
Становление NeoCat как enterprise-компании с комплексными требованиями к производительности, целостности данных, глобальной уникальности и идемпотентности операций потребовало разработки гибридной архитектуры - это проектирование и построение ИТ-систем, которые целенаправленно комбинируют различные архитектурные подходы, парадигмы, технологии или модели развёртывания для достижения оптимального баланса между преимуществами каждой из них.
CREATE TABLE payments (
-- УРОВЕНЬ 1: ПРОИЗВОДИТЕЛЬНОСТЬ
-- Суррогатный ключ для максимальной скорости JOIN внутри БД
payment_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
-- УРОВЕНЬ 2: ГЛОБАЛЬНАЯ ИДЕНТИФИКАЦИЯ
-- UUID для API, интеграций, репликации
payment_uuid UUID DEFAULT uuid_generate_v7() UNIQUE NOT NULL,
-- УРОВЕНЬ 3: БИЗНЕС-ЛОГИКА
-- Естественные ключи для бизнес-правил
payment_number VARCHAR(6) NOT NULL,
payment_date DATE NOT NULL,
client_id BIGINT NOT NULL,
-- УРОВЕНЬ 4: ИДЕМПОТЕНТНОСТЬ И ЦЕЛОСТНОСТЬ
-- Хэш для гарантированной детерминированности
data_hash BYTEA NOT NULL DEFAULT sha256(
( payment_number ||
'|' || payment_date::TEXT ||
'|' || client_id::TEXT
)::bytea
),
-- Данные
amount DECIMAL(10,2),
-- ОГРАНИЧЕНИЯ ДЛЯ КАЖДОГО УРОВНЯ:
-- 1. Бизнес-правила (естественный ключ)
CONSTRAINT uq_business_key UNIQUE (payment_number, payment_date, client_id),
-- 2. Идемпотентность
CONSTRAINT uq_data_hash UNIQUE (data_hash),
-- 3. Референциальная целостность
CONSTRAINT fk_client
FOREIGN KEY (client_id) REFERENCES clients(client_id)
ON DELETE RESTRICT
ON UPDATE CASCADE,
-- 4. Валидация данных
CONSTRAINT chk_amount_positive CHECK (amount >= 0)
);
Гибридный подход позволяет NeoCat достигать компромисса между противоречивыми требованиями: высокая внутренняя производительность обеспечивается компактными числовыми ключами, глобальная уникальность - UUID, целостность бизнес-данных реализуется естественными ключами, а надёжность потоков данных - детерминированными хешами. Главный плюс такой архитектуры оптимизация под конкретные сценарии без глобальных компромиссов, что даёт гибкость для эволюции системы. Однако это достигается ценой значительного усложнения модели данных, роста объёма хранения за счёт дублирования ключей и индексов, а также повышенных требований к квалификации разработчиков, которые должны чётко понимать назначение каждого типа идентификатора в разных контекстах, что увеличивает стоимость поддержки и замедляет онбординг новых членов команды. Не создавайте гибридную архитектуру «на вырост». Начинайте с простого суррогатного ключа и усложняйте схему только тогда, когда столкнётесь с реальными ограничениями, а не гипотетическими сценариями.
Котики разработчики рефлексируют

Путь NeoCat демонстрирует, что каждый тип ключа решает определенный класс задач. Зрелость компании проявилась не в отказе от «старых» ключей, а в понимании, где и когда каждый из них раскрывает свои сильные стороны. Выбор типа ключа — это всегда компромисс между производительностью, масштабируемостью, простотой разработки и бизнес-требованиями, и оптимальное решение зависит от конкретного контекста и стадии развития системы.
Дополнительно: Классификация ключей
Классификация ключей в базах данных — это живая и постоянно развивающаяся область. Из-за многообразия ключей их полезно классифицировать по нескольким критериям. Ниже представлены основные оси классификации.

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

Kahelman
18.12.2025 20:27И кстати ваш пример с user-name, payments, date в приципе не правильный.
Даже если предположить что user-name строго уникальный, payments сам по себе не может быть уникальным.
Если вы 5 раз заплатили по 1 рублю, то все платежи «одинаковые» вам все равно вернут вам деньги с первого платежи или с последнего.
Поэтом здесь не может быть первичного ключа. Даже если вы впихнете поле id Integer Primary Key, это будет “row id” а не первичный ключ в смысле реляционной теории и бизнес-логики.
Я вообще не знаю как тут можно прикрутить первичный ключ и зачем он тут нужен.

neoflex Автор
18.12.2025 20:27С учетом того, что бизнес-процесс был изначально устроен так, что по одному клиенту мог проводиться только один платеж в день выбор ключа PRIMARY KEY (client_name, payment_date) очевиден. И при возврате вернется именно тот платеж, который был совершен в эту дату этим клиентом.

Kahelman
18.12.2025 20:27Бизнес процессы имеют тенденцию меняться. И понятно что не может вот требования один платеж от одного клиента в реальной жизни. Задача изначально была типа сферического коня в вакууме. Если нужна задача для иллюстрации: берите классику: студенты, преподаватели, курсы и оценки. Тогда не придётся придумывать несуществующие ограничения там где их нет

ExiTest
18.12.2025 20:27Мне кажется лучше даже не начинать проек с sql базой. За кажущейся легкостью в начале потом настает час расплаты и много боли. Лучше юзать самую простую бд типа ключ значение и хорошо думать как все индексировать на лету. UUID - dense id связи, roaring bitmap и т.д. "Отшардировать" потом будет тоже проще
Kahelman
Sequence не гарантирует непрерывности. Если не ошибаюсь то гарантировать непрерывность практически невозможно. Либо возможно но гарантировано угробит производительность.
Если нужен аудит то пишут в конце записи хеш, который вычисляют из прядущего хеша и данных записи. Таким образом нельзя внести изменения в данные.
SergeyProkhorenko
Про якобы "минусы" UUIDv7 тоже много чего наврали - понадергали мифов из интернета. В корпоративном блоге уж могли бы делать проверку фактов перед публикацией. Хотя про ужасы натуральных ключей местами хорошо написано - чувствуется выстраданная боль системных аналитиков. Правда, про замену ключей при интеграции систем-источников как-то забыли упомянуть.
neoflex Автор
Упоминаемые недостатки (размер, сложность, предсказуемость) действительно не являются приговором. В статье подсвечиваются риски того, что может быть. Спорить можно только о вероятности появления этого риска. Укажите, пожалуйста, на конкретное утверждение, которое, по вашему мнению, неверно в принципе и такого "не может быть никогда" - мы с благодарностью изучим этот вопрос, возможно и нам это принесет новые знания.
Хотелось бы передать многообразие ключей и причины их появления, поэтому про интеграцию систем и эффективность потоков данных, как раз следующий DWH уровень.
SergeyProkhorenko
Вот эти мифы, не имеющие ничего общего с действительностью:
Больший размер UUIDv7 (16 байт) якобы "снижает эффективность хранения". Загадочный параметр. Если имеется в виду скорость CRUD операций, то в PostgreSQL для UUIDv7 она такая же, как у автоинкремента (подтверждается бенчмарками, а не сомнительным теоретизированием). Если имеется в виду объем БД, то при использовании UUIDv7 устраняется необходимость в поле таймстемпа created_at, а также устраняется необходимость в замене ключей и, соответственно, в промежуточных таблицах при интеграции данных из нескольких источников. То есть, с использованием UUIDv7 объем БД может даже уменьшиться по сравнению с автоинкрементом
Якобы при использовании UUIDv7 имеется "повышенная сложность реализации, требующая поддержки со стороны библиотек и фреймворков". Это совершенно устаревшие сведения. Все ведущие СУБД и языки программирования уже реализовали встроенные функции генерации UUIDv7 (PostgreSQL и даже SQL Server, правда, без толковой документации), или имеют их в стандартных библиотеках (Python) или в самых популярных библиотеках (Golang, Rust). Для Java тоже есть, но я особо не интересовался
Упорядоченность на основе времени якобы раскрывает информацию о моменте создания объекта. Если неумело пользоваться, то раскрывает. Но в PostgreSQL и в Percona Server for MySQL значение таймстемпа в UUIDv7 можно сдвинуть хоть на несколько тысячелетий вперед (и до 1970 года назад)
Упорядоченность на основе времени якобы требует синхронизации системных часов между инстансами для сохранения корректной последовательности. Разные инстансы синхронизируется не между собой, а с мировым временем (по протоколу NTP и др.). Если инстансы находятся очень далеко друг от друга, то задержку сигнала можно компенсировать сдвигом значения таймстемпа. Если все же последовательность незначительно нарушается, то это никак не влияет на эффективность индексов и скорость работы БД
Якобы структура UUIDv7 менее случайна по сравнению с UUID v4, что может быть недостатком в сценариях, где критична полная непредсказуемость идентификаторов. Хакер, предсказавший значение UUIDv7 для строго по RFC 9562 реализованной функции генерации UUIDv7 (в PostgreSQL, Python, Rust и др.), получит нобелевку и золотой бюст на родине героя. Такое предсказание просто невозможно. И, кстати, таймстемп заметно уменьшает и без того нулевые шансы правильного предсказания. А использование UUIDv7, как и UUIDv4 для контроля доступа и других криптоцелей запрещено стандартом RFC 9562
Ключевым преимуществом UUID якобы стала независимо и гарантировано уникальная генерация идентификаторов в любой точке системы без централизованной координации. Часто можно столкнуться с ошибочными мнениями, что UUIDv7 нужны для распределенных систем, а для одного сервера лучше автоинкремент. Но генерировать UUIDv7 можно и на одном сервере, и UUIDv7 первоначально планировались именно для этого, а не для распределенных систем и генерации на клиенте (это лишь дополнительный бонус). UUIDv4 использовались для объединения данных из нескольких таблиц без необходимости замены ключей, но сильно замедляли работу БД. UUIDv7 разрабатывались с той же целью, но должны были и обеспечили скорость обработки данных как у автоинкремента
neoflex Автор
Этот пример это и показывает. Помимо того, что любой SEQUENCE не гарантирует непрерывность числового ряда. Например, при откате транзакции полученное значение теряется безвозвратно. Но даже в "идеальном мире" — без единого отката — использование CASHE - основная причина разрывов.