cv.cm

知識 · 文字、資料與資安

UUID 是什麼?

閱讀約 5 分鐘

簡答

UUID(通用唯一識別碼)是一個 128 位元的數字,用來標記資料,不需要由中央機構發放 ID。它寫成分為五組的 32 位十六進位數字,例如 f47ac10b-58cc-4372-a567-0e02b2c3d479。目前的標準 RFC 9562 定義了多個版本;第 4 版完全隨機,第 7 版則以時間戳記開頭,所以 ID 會依建立時間排序。

開啟UUID 產生

如何解讀 UUID

文字形式共 36 個字元:32 位十六進位數字加 4 個連字號,分組為 8-4-4-4-12。以二進位表示則是 16 個位元組。每個 UUID 都有兩個位置記錄中繼資訊:

  • 版本:第三組的第一位數字。在 f47ac10b-58cc-4372-a567-0e02b2c3d479 中是 4。
  • 變體(variant):第四組的第一位數字。標準 UUID 是 8、9、a 或 b;這裡是 a。

GUID 是 Microsoft 對同一種東西的稱呼,格式完全相同。十六進位的大小寫是等價的;RFC 9562 建議輸出用小寫、輸入不分大小寫。另有兩個特殊值:全為 0 的 Nil UUID,以及全為 f 的 Max UUID。

UUID 的版本

2024 年 5 月發布的 RFC 9562 取代了 RFC 4122,保留第 1 到 5 版,並新增第 6、7、8 版。

版本組成可依時間排序常見用途
1時間戳記(自 1582 年起,以 100 奈秒為單位)+ 時脈序列 + 節點 ID(常是 MAC 位址)以文字排序時不行舊有系統
3命名空間與名稱的 MD5 雜湊否確定性 ID(建議改用 v5)
4122 個隨機位元否通用 ID
5命名空間與名稱的 SHA-1 雜湊否相同輸入永遠產生相同 UUID
6重新排列第 1 版欄位,時間的高位在前是從 v1 遷移
748 位元的 Unix 毫秒時間 + 隨機位元是資料庫主鍵、記錄檔、事件
8由廠商自訂的結構視情況而定實驗性或特定應用

第 3 和第 5 版是確定性的:用 DNS 名稱的命名空間雜湊 example.com,在每台機器上都會得到同一個 UUID。它們使用 MD5 和 SHA-1 只是為了打散位元,而不是為了安全性。

第 4 版與第 7 版比較

位元第 4 版第 7 版
0–47隨機Unix 毫秒時間戳記
48–51版本 0100(4)版本 0111(7)
52–63隨機隨機,或亞毫秒計數器
64–65變體 10變體 10
66–127隨機隨機
隨機位元數122最多 74

RFC 中的第 7 版範例是 017f22e2-79b0-7cc3-98c4-dc0c0c07398f。它的前 12 位十六進位數字 017f22e279b0,代表 Unix 紀元後 1,645,557,742,000 毫秒,也就是 2022-02-22 19:22:22 UTC。

實際差別在於資料庫效能。隨機的 v4 主鍵會落在 B-tree 索引中的任意位置,造成分頁分割,寫入分散到整個索引。依時間排序的 v7 主鍵則是在尾端附近附加,就像自動遞增的整數,插入快速、索引也保持緊湊。新的資料庫主鍵通常選 v7 較好;若是不該透露建立時間的不透明權杖,就用 v4。

到底有多「唯一」?

122 個隨機位元代表第 4 版 UUID 約有 5.3 × 10^36 種可能。依生日界限,要產生約 2.7 × 10^18 個,發生一次碰撞的機率才會達到 50%。以每秒產生 10 億個計算,大約要 86 年。

實際發生的碰撞來自糟糕的隨機性,而不是數學本身。以相同隨機狀態複製出來的虛擬機器,或是建立在 Math.random() 這類非密碼學函式上的產生器,都可能產生重複的值。請使用密碼學安全的來源:瀏覽器和 Node.js 的 crypto.randomUUID()、Python 的 uuid.uuid4(),或 PostgreSQL 的 gen_random_uuid()。

儲存 UUID

  • 有原生型別就用原生型別,例如 PostgreSQL 的 uuid:只佔 16 個位元組,而不是文字的 36 個。
  • MySQL 中請存成 BINARY(16);用文字儲存會讓索引大小增加一倍以上。
  • 比較 UUID 時不分大小寫,或在輸入時統一轉成小寫。
  • 不要試圖從 v4 UUID 解讀出意義。只有版本和變體位元帶有資訊。

常見問題

UUID 和 GUID 有什麼不同?

實務上沒有差別。GUID 是 Microsoft 使用的名稱,格式與版本都和 UUID 相同,同樣是 128 位元。

兩個 UUID 可能會重複嗎?

理論上可能;實務上,只要用安全的隨機來源產生就不會。在第 4 版 UUID 數量遠超過百京(10^18)個之前,發生任何碰撞的機率都小到可以忽略。

該用哪個 UUID 版本?

資料庫主鍵和任何需要依時間排序的情況用第 7 版;ID 不應透露任何資訊時用第 4 版;相同輸入必須永遠產生相同 ID 時用第 5 版。

如何在 JavaScript 中產生 UUID?

呼叫 crypto.randomUUID(),它會以密碼學安全的產生器回傳第 4 版 UUID。在現代瀏覽器的 HTTPS 頁面,以及 Node.js 19 以上版本中都可以直接作為全域函式使用。

所有知識文章