知識 · 文字、資料與資安
UUID 是什麼?
簡答
UUID(通用唯一識別碼)是一個 128 位元的數字,用來標記資料,不需要由中央機構發放 ID。它寫成分為五組的 32 位十六進位數字,例如 f47ac10b-58cc-4372-a567-0e02b2c3d479。目前的標準 RFC 9562 定義了多個版本;第 4 版完全隨機,第 7 版則以時間戳記開頭,所以 ID 會依建立時間排序。
如何解讀 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) |
| 4 | 122 個隨機位元 | 否 | 通用 ID |
| 5 | 命名空間與名稱的 SHA-1 雜湊 | 否 | 相同輸入永遠產生相同 UUID |
| 6 | 重新排列第 1 版欄位,時間的高位在前 | 是 | 從 v1 遷移 |
| 7 | 48 位元的 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 以上版本中都可以直接作為全域函式使用。