建表時你會選一種主鍵策略 —— 而這個決定的影響比想像中大。最常見的兩種是自增整數與 UUID。以下比較兩者,以及何時該用哪個。
自增整數
像 BIGINT AUTO_INCREMENT(Postgres 的 SERIAL)這種欄位,會隨著資料插入依序發出 1、2、3⋯⋯
優點:體積小(4–8 位元組)、人類可讀、天然有序,且索引局部性極佳 —— 新列附加到 B-tree 尾端,插入很快。
缺點:會洩漏資訊(對手看到 /users/5000 就知道你的規模)、可被猜測(授權若不嚴會導致列舉攻擊),而且在分散式或分片系統中很難用,因為兩個節點無法各自獨立產生下一個號碼而不協調。
UUID
UUID 是一組 128 位元識別碼,像 550e8400-e29b-41d4-a716-446655440000。v4 版本是隨機的,任何節點都能無需協調地產生,且碰撞機率趨近於零。你甚至能在送進資料庫前就在前端產生。用 UUID 產生器產生一批就能看到格式。
優點:無需協調即全域唯一、不洩漏數量、無法猜測、可跨資料庫合併。
缺點:較大(16 位元組,文字形式 36 字)、對人不友善,而且關鍵是 —— 隨機的 UUIDv4 會傷害索引局部性。因為新鍵隨機落在 B-tree 各處,插入會造成頁分裂、索引碎片化,在大表上拖慢寫入。
折衷方案:UUIDv7 / ULID
你不必在「到處唯一」與「索引友善」之間二選一。時間排序的 ID,像 UUIDv7 與 ULID,前綴內嵌時間戳,因此既全域唯一又大致有序 —— 恢復索引局部性,同時保有 UUID 的分散式友善性。對想要 UUID 好處又不想付出寫入代價的新系統,這越來越成為預設。
怎麼選
- 小型、單一資料庫、內部 ID? 自增簡單又快。
- 對外公開的 ID,或想隱藏規模? 用 UUID(或對外用 UUID、內部仍保留整數主鍵)。
- 分散式、分片、或前端產生 ID? 用 UUID —— 為了索引效能最好用 UUIDv7/ULID。
- 絕不用連續 ID 當安全機制;無論鍵多好猜,授權都必須確實執行。
一句話結論
自增贏在簡單與原始索引效能;UUID 贏在唯一性、隱私與分散式。想兼得,就用時間排序的 UUIDv7/ULID。
現在就需要識別碼?免費的 UUID 產生器在你的瀏覽器產生 RFC 4122 v4 ID —— 可批次產生、一鍵複製。