
UUID v1、v4、v7 怎樣選擇?RFC 9562、資料庫排序與碰撞風險
選擇 UUID 版本,不只是決定要不要隨機數。v1、v4、v7 同樣佔 128 位元,但會透露甚麼資料、怎樣排序,以及適合甚麼用途,都有所不同。2024 年的 RFC 9562 取代 RFC 4122,加入 v6、v7、v8。以下從位元配置說明各版本,並指出不能只憑版本名稱推定的唯一性、時間順序與安全性保證。
日文原文發布: 2026-04-18
UUID 的共通結構:128 位元與版本欄位
UUID 長度為 128 位元,即 16 個位元組。常見文字表示含 32 個十六進制數字與 4 個連字號,分組為 8-4-4-4-12:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
M 是版本:以 0 起算的位元位置 48~51,也就是不計連字號的第 13 個十六進制數字。變體(variant)欄位從位元 64 開始;本文討論的 RFC 變體使用前兩位 10,因此 N 會是 8、9、a 或 b。
版本占 4 位元,這個變體占 2 位元,其餘共 122 位元依版本分配。Nil 與 Max UUID 則是規格另行定義的特殊值,不應用一般版本欄位的讀法強行分類。
UUID v1:時間戳記與節點識別碼
v1 使用從 1582 年 10 月 15 日起算、以 100 納秒為單位的 60 位元時間戳記,並包含時鐘序列與 48 位元節點識別碼。節點欄位可以根據 MAC 地址,也可以使用符合規則的隨機值。
時間欄位以低位部分在前的方式分散存放,因此標準欄位順序不適合直接作長時間範圍的時間排序。某些範圍內看似遞增,不代表跨欄位回繞仍保持順序。
若節點欄位使用真實 MAC 地址,對外公開的 UUID 可能洩露節點資訊;時間戳記也提供產生時間的線索。既有系統若依賴 v1 的欄位配置,升級前須確認相依性。
UUID v4:122 個隨機位元
v4 除固定的版本與變體位元外,其餘 122 位元由隨機或偽隨機資料填入,不嵌入時間或節點資訊。可能值約有 2^122 ≈ 5.3 × 10^36 個。
若每次產生都獨立且均勻,產生 10 億個 UUID 時,至少發生一次碰撞的機率近似 9.4 × 10−20。這是生日問題的近似值,不是對有缺陷隨機數產生器的保證;唯一索引等衝突防護仍有用途。
隨機主鍵在 B-tree 索引中的寫入位置較分散,可能影響區域性與頁面分割。但實際成本取決於資料庫、索引、快取與工作負載,不能把「v4 一定慢」當成通則。
UUID v7:將 Unix 毫秒時間放在最前面
v7 的高 48 位元存放自 Unix epoch 起算的毫秒時間戳記,其餘欄位如下:
unix_ts_ms:48 位元
version: 4 位元
rand_a: 12 位元
variant: 2 位元
rand_b: 62 位元
扣除版本與變體後的 74 位元,依實作可包含隨機資料、次毫秒時間或計數器,不是一律 74 位元都隨機。不同毫秒的值若按 RFC 位元組順序或無號 128 位元整數比較,時間戳記會決定先後。以標準文字表示排序時,還須統一十六進制字母大小寫,並採用相符的字元碼排序;使用資料庫原生 UUID 類型時,應確認產品定義的比較順序。
同一毫秒內不會自動依產生順序排序。這需要實作採用次毫秒精度、計數器或其他單調遞增策略,並處理並行產生、時鐘回退與計數器容量。
內嵌時間戳記不能作為業務事件或審計時間的權威紀錄。它可能受時鐘、產生器策略或時間調整影響。需要精確事件時間時,仍應另存 created_at 等欄位,依應用需求決定可信的時間來源。
RFC 9562 建議在可行時,以 v7 取代需要時間型 UUID 的 v1、v6;這不代表所有 v4 都必須改成 v7。v4 不透露建立時間的特性,可能正是需求的一部分。
截至 2026 年 9 月查核,已正式發佈的 PostgreSQL 18 提供 uuidv7(),也提供 uuid_extract_timestamp() 等函式。是否適合改用 v7,仍應以自己的資料庫與負載實測。
v6 與 v8 的定位
- v6:重新排列 v1 的時間欄位,讓高位時間在前,適合有 v1 相容背景的遷移情境。
- v8:保留版本與變體欄位,讓其餘 122 位元由應用自行定義。自訂配置不會自動獲得唯一性、時間排序或安全性保證,這些都須由產生與使用規則建立。
Nil 與 Max UUID:特殊邊界值
Nil: 00000000-0000-0000-0000-000000000000
Max: ffffffff-ffff-ffff-ffff-ffffffffffff
Nil 的全部 128 位元為 0,Max 則全部為 1。它們可用作特殊標記或邊界值,但「未設定」「最大值」等實際應用語義必須自行約定,不能假設每個資料庫或 API 都有相同解讀。
依用途選擇版本
如表格未能完整顯示,可左右捲動。
| 用途 | 候選 | 注意事項 |
|---|---|---|
| 新資料庫主鍵 | v7 | 評估時間區域性,並以實際資料庫測試 |
| 公開 API 資源識別碼 | v4 或 v7 | 考量是否可透露時間;識別碼不能取代授權檢查 |
| 安全 token | 專用 token 產生機制 | 若介面強制要求 UUID,至少使用密碼學安全隨機數產生 v4,並另外設計有效期與授權 |
| 分散式日誌識別碼 | v7 | 考量時鐘、同毫秒順序與重複處理;事件時間另存 |
| 既有系統整合 | 原有 v1 或 v4 | 先確認版本與欄位相依性 |
| 自訂位元配置 | v8 | 自行定義碰撞與互通性規則 |
常見實作問題
- 儲存形式:含連字號的常見文字表示有 36 個字元,而二進制值是 16 個位元組。實際儲存成本還受資料類型、編碼、索引與資料庫額外開銷影響。
- v7 的同毫秒順序:不要只看名稱就假設每次產生都嚴格遞增。檢查產生器的並行處理、隨機數、計數器與時鐘回退策略。
- 隨機數來源:安全性敏感用途不要使用
Math.random()自行拼接。可使用平台提供的crypto.randomUUID()或 Python 的uuid.uuid4()等既有介面,並確認執行環境的安全性需求。
瀏覽器的 crypto.randomUUID() 產生 v4,且僅能在安全環境(secure context,例如 HTTPS)中使用。無論版本為何,都不應把難猜的 ID 當成存取控制。
重點整理
- UUID 是 128 位元;標準文字表示的版本位於第三組開頭。
- v1 包含時間與節點資訊,原始欄位順序不適合長時間範圍的時間排序。
- v4 有 122 個隨機位元,不嵌入建立時間。
- v7 將 48 位元 Unix 毫秒時間放在前面,但同毫秒順序與資料庫比較方式仍須確認。
- v8 的自訂配置不附帶自動的唯一性或安全性保證。
- 使用可靠隨機數來源、合適的儲存類型,並把授權與事件時間獨立設計。
參考資料及來源
編輯說明
本文使用 AI 協助編輯,並在發布前由編輯核對。內容仍可能包含事實、理解或時效上的錯誤;作出重要決定前,請查閱所列的一手資料或官方文件。

