Hai cách sinh khóa chính:
- Auto-increment (
SERIAL/BIGSERIAL): số tăng dần, nhỏ gọn (4/8 byte), index B-tree gọn, dễ debug. Nhược: lộ thông tin (đối thủ đoán được số bản ghi qua id), và không an toàn cho hệ phân tán vì cần bộ đếm trung tâm. - UUID v4: 128-bit ngẫu nhiên, duy nhất toàn cục không cần phối hợp — hợp microservices. Nhược: ngẫu nhiên nên chèn vào vị trí lung tung → phân mảnh index B-tree (page split, phình), to gấp ~4 lần int, khó đọc.
- UUID v7 (RFC 9562): có tiền tố timestamp + phần ngẫu nhiên → vừa tăng dần như auto-increment (thân thiện B-tree, không phân mảnh), vừa duy nhất toàn cục, lại sắp được theo thời gian tạo. Là lựa chọn tốt nhất khi cần UUID.
Quy tắc chọn:
- UUID khi: id công khai (URL/API — tránh dò tuần tự), hệ phân tán, hoặc cần sinh id ở client trước khi ghi DB.
- BIGINT auto-increment khi: bảng nội bộ không lộ ra ngoài, bảng nặng JOIN cần hiệu năng cao.
(PostgreSQL 17+ có sẵn gen_random_uuid() cho v4; v7 dùng extension pg_uuidv7 hoặc sinh ở app.)
Two ways to generate a primary key:
- Auto-increment (
SERIAL/BIGSERIAL): an increasing number, compact (4/8 bytes), keeps the B-tree index tight, easy to debug. Cons: leaks information (rivals can guess record counts from the id), and is unsafe for distributed systems because it needs a central counter. - UUID v4: 128-bit random, globally unique with no coordination — great for microservices. Cons: being random, it inserts at scattered positions → B-tree index fragmentation (page splits, bloat), ~4x larger than an int, hard to read.
- UUID v7 (RFC 9562): a timestamp prefix + random part → both increasing like auto-increment (B-tree friendly, no fragmentation) and globally unique, plus sortable by creation time. The best choice when you need a UUID.
Selection rule:
- UUID when: public-facing ids (URLs/APIs — avoid sequential enumeration), distributed systems, or ids generated client-side before the DB write.
- BIGINT auto-increment when: internal tables not exposed externally, JOIN-heavy tables needing top performance.
(PostgreSQL 17+ ships gen_random_uuid() for v4; for v7 use the pg_uuidv7 extension or generate it in the app.)