bigint з послідовністю:
- компактний (8 байтів), швидкі індекси й
JOIN; - значення зростають - нові рядки дописуються в кінець індексу;
- але розкриває інформацію:
/orders/1042каже, скільки замовлень у вас було, і дозволяє перебирати чужі ID; - генерується лише базою - не можна створити ID до вставки чи в іншій системі.
UUID (16 байтів):
- можна генерувати будь-де: у застосунку, на клієнті, в офлайн-режимі, в кількох базах без конфліктів;
- не розкриває кількість записів і не підбирається;
- зручно для злиття даних з різних джерел і публічних посилань.
Проблема UUIDv4 - випадковість. Нові значення потрапляють у випадкові місця B-tree індексу. На великій таблиці це означає постійні вставки в різні сторінки, розщеплення сторінок, роздутий індекс, гірше використання кешу - вставка помітно повільніша, ніж з послідовним ключем.
UUIDv7 (RFC 9562) починається з мітки часу в мілісекундах, а далі - випадкова частина. Значення приблизно впорядковані за часом, тож вставляються в кінець індексу, як bigint, зберігаючи переваги UUID.
-- PostgreSQL 18+
id uuid PRIMARY KEY DEFAULT uuidv7()
У старіших версіях PostgreSQL UUIDv7 генерують у застосунку: у Laravel - Str::uuid7(), а трейт моделі HasUuids у свіжих версіях фреймворку генерує саме UUIDv7.
Нюанс UUIDv7: мітка часу всередині розкриває момент створення запису. Для більшості даних це неважливо, але якщо час створення - чутлива інформація, це варто врахувати.
Поширений компроміс: внутрішній bigint-ключ для зв'язків і швидкості плюс окрема унікальна колонка public_id (UUID чи коротший ідентифікатор) для URL і API.