UUID 指南:版本、格式與最佳實踐
UUID(通用唯一識別碼)是 128 位元的識別碼,設計目的是在無需中央管理機構的情況下,在空間和時間上保持唯一性。對於需要獨立產生 ID(無需協調)的分散式系統而言,UUID 是標準的首選方案。
UUID 格式
UUID 是一個 128 位元的數字,以 32 個十六進位數字呈現,分為五組並以連字號分隔:
550e8400-e29b-41d4-a716-446655440000
^^^^^^^^ ^^^^ ^^^^ ^^^^ ^^^^^^^^^^^^
time-low mid hi clk node
+ver +var
- 總計:128 位元(16 位元組)
- 字串長度:36 個字元(32 個十六進位字元 + 4 個連字號)
- 版本:編碼於第 13 個字元(「hi」半位元組)
- 變體:編碼於第 17 個字元
使用我們的 UUID 產生器即可立即產生 UUID。
UUID 版本
UUID v1:基於時間
根據當前時間戳記和機器的 MAC 位址產生。
// 結構:時間戳記(60 位元)+ 時鐘序列(14 位元)+ 節點(48 位元)
6ba7b810-9dad-11d1-80b4-00c04fd430c8
優點:可按建立時間自然排序,每台機器保證唯一性。 缺點:會暴露 MAC 位址(隱私疑慮),可能洩漏建立時間。 適用時機:需要時間排序且處於受控環境時。
UUID v4:隨機
由密碼學安全的隨機數產生。這是最廣泛使用的版本。
// 122 個隨機位元(6 個位元保留給版本和變體)
f47ac10b-58cc-4372-a567-0e02b2c3d479
優點:簡單、不洩漏資訊、無需協調。 缺點:無法排序,資料庫索引效能略遜於序列 ID。 適用時機:通用場景——這是大多數應用程式的預設選擇。
UUID v7:時間排序隨機(新標準)
最新版本(RFC 9562,2024),結合 Unix 時間戳記與隨機資料。
// 結構:時間戳記(48 位元)+ 隨機(74 位元)
018e7b50-4a00-7000-8000-000000000001
優點:自然按時間排序、優秀的資料庫索引效能、除毫秒精度外不洩漏資訊。 缺點:較新,部分函式庫可能尚未支援。 適用時機:需要按時間順序排列的唯一 ID——非常適合作為資料庫主鍵。
其他版本
- UUID v3:基於命名空間和名稱的 MD5 雜湊。具確定性。
- UUID v5:基於命名空間和名稱的 SHA-1 雜湊。具確定性,優先於 v3 使用。
- UUID v6:重新排列的 v1,提升排序能力。已被 v7 取代。
- Nil UUID:全零(
00000000-0000-0000-0000-000000000000)。用作哨兵值。
碰撞機率
隨機產生的 UUID(v4)碰撞的可能性有多大?以 122 個隨機位元計算:
- 產生 10 億個 UUID 後:機率約為 10^18 分之 1
- 要達到 50% 的碰撞機率:需要大約 2.7 × 10^18 個 UUID
- 以每秒 10 億個 UUID 的速度:大約需要 86 年
就所有實際用途而言,UUID v4 碰撞不會發生。你遇到硬體故障的機率遠高於碰撞。
UUID 與其他 ID 格式比較
| 格式 | 長度 | 可排序 | 唯一 | URL 安全 |
|---|---|---|---|---|
| UUID v4 | 36 字元 | 否 | 是 | 是 |
| UUID v7 | 36 字元 | 是 | 是 | 是 |
| ULID | 26 字元 | 是 | 是 | 是 |
| nanoid | 21 字元 | 否 | 大致是 | 是 |
| 自動遞增 | 不定 | 是 | 單表內 | 是 |
| Snowflake ID | 18-19 字元 | 是 | 單系統內 | 是 |
ULID(通用唯一字典排序識別碼)
ULID 是一種精簡的替代方案:48 位元時間戳記 + 80 位元隨機數,編碼為 26 個 Crockford Base32 字元。它們可按建立時間進行字典序排序。
何時使用自動遞增 ID
對於單一資料庫應用程式,序列 ID 更簡單且更高效。在以下情況下使用 UUID:
- ID 由多個系統獨立產生
- 不希望向外部使用者暴露插入順序
- 需要適合分散式資料庫合併的 ID
資料庫效能考量
隨機 UUID(v4)會導致 B-tree 索引碎片化,因為插入發生在隨機位置。在大型資料表上,這可能使寫入效能下降 2-5 倍。
解決方案:
- 使用 UUID v7:時間排序的 UUID 按順序插入,效能與自動遞增相當
- 以二進位儲存:使用
BINARY(16)取代CHAR(36)可節省 55% 儲存空間 - 使用 ULID:可排序且比 UUID 更精簡
-- PostgreSQL:原生 UUID 類型(16 位元組,高效)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL
);
-- MySQL:以 BINARY(16) 儲存以提升效能
CREATE TABLE users (
id BINARY(16) PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
產生 UUID
命令列
# macOS/Linux
uuidgen
# Python 單行指令
python3 -c "import uuid; print(uuid.uuid4())"
JavaScript
// 內建方法(Node.js 19+、現代瀏覽器)
crypto.randomUUID();
// UUID v7(使用 uuid 套件)
import { v7 } from 'uuid';
const id = v7();
Python
import uuid
uuid.uuid4() # Random
uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com') # Name-based
如需快速產生 UUID 而不需撰寫程式碼,我們的 UUID 產生器可在瀏覽器中即時建立 v4 UUID。
常見問題
資料庫主鍵應該使用 UUID 還是自動遞增整數?
對於單一資料庫應用程式,自動遞增整數更簡單且更快速。對於分散式系統、微服務,或者需要在資料庫插入前於客戶端產生 ID 的情況,UUID(最好是 v7)是更好的選擇。如果你使用 PostgreSQL,原生 UUID 支援使得效能差異可以忽略不計。
UUID 可以用作安全令牌嗎?
UUID v4 使用來自密碼學來源的 122 位元隨機數,提供良好的熵值。然而,對於安全令牌(API 金鑰、Session ID),最好使用專門設計的令牌格式,這些格式具有額外的屬性,如校驗碼、過期時間編碼或前綴識別。UUID 的用途是身分識別,而非驗證。
相關資源
- UUID 產生器 — 線上即時產生 UUID
- 雜湊演算法比較 — 了解 UUID v3 和 v5 背後的雜湊函式
- JSON API 設計模式 — 在 API 回應中有效使用 UUID