UUID v1、v4、v7 怎樣選擇?RFC 9562、資料庫排序與碰撞風險
DDEVELOPER
開發發布: 8 分鐘閱讀

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 會是 89ab

版本占 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 協助編輯,並在發布前由編輯核對。內容仍可能包含事實、理解或時效上的錯誤;作出重要決定前,請查閱所列的一手資料或官方文件。

相關文章