Какой тип ID является последовательным?
Что проверяют
Понимаете ли вы, как тип ключа влияет на индекс, вставку и генерацию в распределённой системе. Следом почти всегда спрашивают, почему UUIDv4 плох как первичный ключ и чем его заменить.
Как отвечать
Последовательными или хотя бы растущими по времени бывают:
- автоинкремент:
BIGSERIALилиGENERATED ALWAYS AS IDENTITYв PostgreSQL,AUTO_INCREMENTв MySQL. Компактныйint64, вставка всегда в правый край B-tree. Минус: ID выдаёт база, он неизвестен до вставки, а при шардировании нужна координация; - UUIDv7: описан в RFC 9562. Первые 48 бит это Unix-время в миллисекундах, дальше случайная часть, поэтому ключи сортируются по времени создания и не разбрасывают вставки по индексу. В Go есть
uuid.NewV7()в пакетеgithub.com/google/uuid, в PostgreSQL 18 появилась встроеннаяuuidv7(); - ULID: та же идея в 128 битах, записывается 26 символами Crockford Base32;
- Snowflake-подобные ID: 64 бита из времени, номера узла и счётчика. Помещаются в
int64и генерируются без обращения к базе.
UUIDv4 полностью случайный: каждая вставка попадает в случайную страницу индекса, растут промахи кеша и расщепления страниц. UUIDv1 содержит время, но младшие биты времени стоят первыми, поэтому по байтам он не сортируется; для этого и появились v6 и v7.
В Go держите UUID как uuid.UUID (это [16]byte), а в базе как тип uuid на 16 байт, а не строкой на 36 символов.
Где спотыкаются
Называют UUIDv1 последовательным. Время внутри есть, но порядок байт его не отражает.
Считают автоинкремент непрерывным и упорядоченным по коммиту. Значения последовательности не возвращаются при откате, так что дыры нормальны, а транзакция с меньшим ID может закоммититься позже соседней.
Забывают про утечку информации: по растущему ID в URL видно число заказов, и его легко перебрать. Для внешних ссылок отдают UUID или отдельный публичный ключ. А Snowflake-ID больше 2^53 теряют точность в JavaScript, поэтому в JSON их отдают строкой.