GUID 版本詳解:v1–v7 該選哪個?
2026-07-09
Tags: Windows · GUID · 科普 · QuickGUID
開啟任何一個 UUID 函式庫,你會看到 uuid1()、uuid3()、uuid4()、uuid5(),以及越來越常見的 uuid7()。規範總共定義了八個版本。你到底該用哪一個?
簡短回答:絕大多數場景用 v4,資料庫主鍵用 v7,需要相同輸入每次都產生同一個 GUID 時用 v5。 本文剩下的部分解釋原因 —— 附帶位元組布局、每個版本存在的真實理由,以及一份按語言分類的程式碼速查表。
如果你是 GUID 新手,建議先看 什麼是 GUID? 了解結構和唯一性的基礎。本文是它的技術姊妹篇,對每個版本深入展開。
GUID/UUID 版本全景
每個版本都是填充同樣 128 位元的另一種 配方。版本 nibble(第三段的首位十六進位數字)告訴你用了哪種配方。
| 版本 | 產生來源 | 可排序 | 典型用途 |
|---|---|---|---|
| v1 | 時間 + MAC | 是 | 舊系統(隱私風險) |
| v2 | DCE Security | 是 | 罕見,專用 |
| v3 | MD5 命名空間雜湊 | 否 | 已棄用(用 v5) |
| v4 | 隨機 | 否 | 通用預設值 |
| v5 | SHA-1 命名空間雜湊 | 否 | 確定性 ID |
| v6 | 重排後的 v1 時間 | 是 | 直接取代 v1 |
| v7 | 毫秒時間戳 | 是 | 資料庫主鍵 |
| v8 | 廠商自訂 | 自訂 | 專用 |
v1、v4、v5、v7 覆蓋了 99% 的實際使用。下面逐一展開。
v1:時間與 MAC 位址
v1 是 RFC 4122 的原始配方。它把三樣東西塞進 128 位元:
| time_low (32) | time_mid (16) | ver+time_hi (16) | var+clk_seq (16) | node/MAC (48) |- 60 位元時間戳 —— 自 1582-10-15(格里曆採用日)起的 100 奈秒間隔。時間戳分散在
time_low、time_mid、time_hi中。 - 14 位元時脈序列 —— 一個計數器,用於區分同一時脈節拍內產生的兩個 GUID,或系統時脈被回調的情況。
- 48 位元節點 —— 網路卡的 MAC 位址。
MAC 位址的問題
節點欄位是 硬體指紋。你發布的每一個 v1 GUID 都帶著你機器的 MAC 位址 —— 而且與 IP 位址不同,MAC 位址被設計為全域唯一且持久不變。這是真實的隱私外洩。
這不是理論問題。研究人員已經證明,透過讀取檔案元資料中嵌入的 v1 GUID,就能把文件追溯到建立它的那台機器。微軟自己在這一情況被演示之後,就把 v1 產生從 Office 遙測中移除了。現代作業系統出於同樣原因,也會對展示給 Wi-Fi 網路的 MAC 做隨機化。
結論: 新程式碼避免使用 v1。它在舊系統、COM 介面和某些硬體相關工具裡倖存 —— 但今天沒有任何理由自己產生它。
v2:DCE Security
v2 是你基本上永遠不會遇到的版本。它沿用 v1 的布局(時間戳 + MAC),在其上疊加一層 POSIX UID/GID —— 即 DCE(分散式運算環境)安全模型中的本地使用者與群組識別碼 —— 讓 UUID 在唯一性之外還能攜帶存取控制資訊。
v2 專為舊企業系統中的 DCE/RPC 驗證和 ACL 而存在。除非你在維護明確使用 DCE Security 的軟體,否則你永遠不會產生或消費 v2。它在這裡出現純粹是為了讓版本列表完整,免得你某天看到那個 nibble 裡的「2」時犯嘀咕。
v3:為什麼它被棄用
v3 與 v5 完全相同,只是用 MD5 取代 SHA-1。MD5 存在實際碰撞攻擊 —— 兩個不同輸入可以被精心構造出同一個雜湊。這在對抗場景下破壞了 v3 的確定性保證。
RFC 4122 為了向後相容保留 v3,但 v5 已經取代了它。今天沒有任何理由產生 v3。如果在野外遇到 v3,把它當舊系統處理。
v4:隨機的預設值
v4 是幾乎所有「產生 GUID」呼叫 [guid]::NewGuid()、Guid.NewGuid()、crypto.randomUUID()、uuid.uuid4()、NEWID() 回傳的東西。它用密碼學強隨機填充 128 位元中的 122 位元(其餘 6 位元是版本和變體標記)。
沒有時間戳、沒有 MAC、沒有機器狀態 —— 純隨機。這讓 v4 可以安全暴露、平行化極其簡單,且對任何現實工作負載都具有足夠的抗碰撞能力。完整的碰撞數學(以及網路上流傳的「十億年」說法為什麼把生日悖論搞錯了)見 主文章。
結論: 這就是你的預設值。除非有具體理由選別的,否則就選 v4。
v5:確定性命名空間 ID
這是多數開發者聽說過卻從沒真正用過的版本 —— 而它解決了一個真正有用的問題。
v5 讓你從 相同 的輸入每次都推導出 相同 的 GUID。給它一個命名空間 UUID 和一個名稱字串,它回傳一個確定性識別碼:
import uuid
# 相同輸入 → 相同 GUID,每次執行,每台機器
dns_guid = uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com')
url_guid = uuid.uuid5(uuid.NAMESPACE_URL, 'https://prunelab.net/blog/guid-explained')
print(dns_guid) # 始終 cf14e0a3-...(同一個值)
print(dns_guid == uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com')) # True工作原理
在內部,v5 把命名空間 UUID 位元組與名稱的 UTF-8 位元組串接起來,對結果執行 SHA-1,取前 16 個位元組,然後蓋上版本(5)和變體位元。命名空間本身就是一個 UUID —— NAMESPACE_DNS、NAMESPACE_URL、NAMESPACE_OID、NAMESPACE_X500 是預先定義的,但任何 UUID 都能當命名空間用。
v5 什麼時候是對的工具
- 可重現的測試夾具 —— 為測試資料產生跨執行穩定的 ID,讓失敗的測試每次指向同一個實體。
- URL 衍生識別碼 —— 不查資料庫就把一個 URL 變成 GUID。兩個系統分別獨立計算同一個 URL 的
uuid5(NAMESPACE_URL, url),結果永遠一致。 - 冪等去重 —— 同一筆記錄匯入兩次,GUID 與自身碰撞,於是光靠鍵就能識別重複。
與 v4 的關鍵對照:v4 每次呼叫回傳一個唯一值(即便輸入相同);v5 對相同輸入回傳穩定值。兩者不可互換。
結論: 每當需要一個 可重現地 從某輸入字串推導出來的 GUID 時,就用 v5。
v6:你大概用不到的 v1 修正版
v6 包含與 v1 完全相同的資料 —— 同樣的時間戳、時脈序列和 MAC —— 但重新組織時間戳位元,讓數值能自然按時間先後排序。在 v1 裡時間戳被笨拙地拆分(low、mid、high);在 v6 裡它按 high-first 儲存,所以字串的字典排序就等於時間排序。
v6 於 2024 年與 v7 一起在 RFC 9562 中標準化。它主要作為 直接遷移路徑,服務於那些已經綁定 v1 時脈加 MAC 模型的系統:保留現有的時間戳邏輯,只重寫位元布局即可。
對於新系統,v7 幾乎總是更好的選擇。 v7 用毫秒時間戳(比 v1/v6 的 100 奈秒格里計數更簡單),不嵌入 MAC 位址,隨機填充也更乾淨。v6 回答的是「如何在不改變產生模型的前提下現代化 v1」;v7 回答的是「今後該用什麼」。
v7:面向資料庫的時間排序
v7 是自 v4 以來最重要的新增版本。它解決 v4 在資料庫裡造成的問題。
資料庫裡的 v4 問題
當資料庫用 GUID 當主鍵時,這些鍵支撐一個 B+ 樹索引。當插入大致有序時,B+ 樹保持高效 —— 新值落在右邊緣,填充已有頁。隨機 v4 GUID 散落在整個鍵空間裡,於是每次插入都命中一個隨機頁。在大表上這會導致頻繁的頁分裂、索引碎片化、快取顫簸和寫入放大。SQL Server 的解法(NEWSEQUENTIALID())是一個專有的、不可移植的 hack,而且會外洩順序資訊。
v7 的布局
| unix_ts_ms (48) | ver (4) | rand_a (12) | var (2) | rand_b (62) |- 48 位元毫秒級 Unix 時間戳 —— 首欄位,所以數值隨時間增長。
- 4 位元版本 —— 設為
7。 - 12 位元 rand_a —— 隨機,或者可選地用一個單調計數器在同一毫秒內排序。
- 2 位元變體 —— 標準 RFC 9562 標記。
- 62 位元 rand_b —— 隨機。
由於時間戳在前,連續產生的 v7 GUID 天然有序:索引插入集中在右邊緣,頁乾淨地填滿,B+ 樹表現就像在用自增整數一樣 —— 同時仍然全域唯一,不需要中央協調器。
什麼時候 v7 不值得
- 記憶體儲存(Redis、memcached)—— 沒有 B+ 樹,沒有碎片化代價。v4 就行。
- 小表 —— 在百萬列以下,v4 與 v7 的差異看不見。
- 非鍵欄位 —— 如果 GUID 只是被儲存的屬性而非索引鍵,順序無關。
- 必須不透明的 GUID —— v7 會外洩產生的毫秒數,在安全敏感場景下可能不受歡迎。
結論: 如果 GUID 是真實資料庫上的叢集主鍵,用 v7。否則 v4。
v8:廠商自訂
v8 是逃生艙:RFC 9562 允許廠商自訂位元布局,只要版本 nibble 為 8 且變體位元正確即可。其餘一切 —— 時間戳位元寬度、隨機性來源、編碼方式 —— 都由實作者決定。
你只會在那些為特定原因設計了自訂 UUID 方案的系統裡見到 v8(比如把分片 ID 或節點 ID 烤進 UUID 用於路由)。如果你不是在建這樣的系統,v8 與你無關;如果你是,規則由你自己的方案定義,而不是這篇文章裡的任何東西。
你到底該用哪個版本?
一份決策指南:
- 「產生通用 ID?」 → v4。 這是 90% 情況下的答案。
- 「資料庫主鍵,或需要時間排序?」 → v7。 特別是大表上的叢集索引。
- 「需要相同輸入每次都得到相同 GUID?」 → v5。 從字串做確定性映射。
- 「在與一個期望 v1 的舊系統打交道?」 → v1(保持相容),但規劃遷移到 v7。
- 「有人建議我用 v3?」 → 別。改用 v5(v3 的 MD5 已經被攻破)。
- 「我想要最新的。」 → 這不是理由。v7 新 而且 解決了真實問題(資料庫排序);v6 新 而且 主要是 v1 的遷移助手。按用途選,不按新舊選。
如果還是拿不準,就用 v4。預設值的存在是有理由的。
按版本和語言產生 GUID
| 語言 / 工具 | v4(預設) | v5(確定性) | v7(有序) |
|---|---|---|---|
| PowerShell | [guid]::NewGuid() | — | — |
| C# / .NET | Guid.NewGuid() | — | Guid.CreateVersion7() (.NET 9+) |
| Python | uuid.uuid4() | uuid.uuid5(uuid.NAMESPACE_URL, 'name') | uuid.uuid7() (3.14 beta) / 函式庫 |
| JavaScript | crypto.randomUUID() | — | (npm uuid v11+) |
| Node.js (uuid 函式庫) | uuid.v4() | uuid.v5('name', NAMESPACE) | uuid.v7() |
| SQL Server | NEWID() | — | — |
| PostgreSQL | gen_random_uuid() | — | (擴充) |
幾點說明:截至 2026 年,v7 的原生支援仍在陸續落地到標準函式庫。Node.js 的 uuid 套件(v11+)和 .NET 9 原生提供;Python 在 3.14 加入 uuid.uuid7();更舊的執行階段需要函式庫。v5 支援幾乎無處不在,因為它純粹是 SHA-1 數學,不需要熵源。
常見問題
v7 會取代 v4 成為預設值嗎?
不會。v4 仍是通用預設。v7 只在 GUID 是有序主鍵時勝出 —— 對大多數其他用途(工作階段權杖、請求 ID、內容雜湊、一切非資料庫場景),v4 的隨機性不是缺點,而 v7 的首位時間戳只會在沒有收益的情況下外洩時序資訊。
v1 現在還安全嗎?
不安全。v1 嵌入你網路卡的 MAC 位址,那是一個持久的硬體指紋。微軟自己在研究人員透過文件裡嵌入的 GUID 追蹤到機器之後,就把 v1 從 Office 遙測裡移除了。新程式碼完全避免 v1;舊 v1 則規劃遷移到 v7。
v3 和 v5 有什麼區別?
兩者都是確定性命名空間雜湊(相同輸入 → 相同 GUID)。v3 用 MD5,v5 用 SHA-1。MD5 有實際碰撞攻擊,所以 v3 在完整性用途上被視為已被攻破,被 v5 取代。今天沒有理由產生 v3。
能把 v4 GUID 轉換成 v7 嗎?
不能。版本不是可以隨便換的標籤 —— 每個版本使用完全不同的產生邏輯。v4 沒有時間戳可提取,所以「得到一個 v7」的唯一辦法是產生一個新的。如果要把一個 v4 主鍵欄位遷移到 v7,實際上是加一個新欄位並重寫它。
.NET 原生支援 v7 嗎?
支援。Guid.CreateVersion7() 在 .NET 9(2024 年 11 月發布)中加入。如果你在 .NET 8 或更早版本上,使用 GenVault 或 UUIDv7 NuGet 套件,或者升級。
QuickGUID:產生 v4 和 v7,轉換任意格式
對於日常的 GUID 工作,QuickGUID 是一款原生 Windows 工具箱,覆蓋完整工作流程:
- 批次產生 v4 或 v7,一次最多 1,000 個
- 10+ 格式轉換:標準、無連字號、花括號、Base64、C 位元組陣列、
DEFINE_GUID巨集 —— 全部帶即時預覽 - 智慧擷取:貼上日誌或原始碼,自動找到並轉換每一個 GUID
- 即時裝飾:引號、前綴/後綴、大小寫 —— 全域切換後直接複製
完全免費,100% 離線。
結尾
版本系統之所以存在,是因為不同的工作需要不同的保證:v4 給你不可追蹤的隨機性,v5 給你可重現性,v7 給你有序性。預設選 v4,在資料庫鍵上用 v7,當相同輸入必須產生相同 GUID 時用 v5。
GUID 新手?先看 什麼是 GUID?,了解結構、連字號格式,以及為什麼 128 位元足以讓碰撞在實際中不成為問題。