Skip to content

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舊系統(隱私風險)
v2DCE Security罕見,專用
v3MD5 命名空間雜湊已棄用(用 v5)
v4隨機通用預設值
v5SHA-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_lowtime_midtime_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 和一個名稱字串,它回傳一個確定性識別碼:

python
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_DNSNAMESPACE_URLNAMESPACE_OIDNAMESPACE_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# / .NETGuid.NewGuid()Guid.CreateVersion7() (.NET 9+)
Pythonuuid.uuid4()uuid.uuid5(uuid.NAMESPACE_URL, 'name')uuid.uuid7() (3.14 beta) / 函式庫
JavaScriptcrypto.randomUUID()(npm uuid v11+)
Node.js (uuid 函式庫)uuid.v4()uuid.v5('name', NAMESPACE)uuid.v7()
SQL ServerNEWID()
PostgreSQLgen_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 或更早版本上,使用 GenVaultUUIDv7 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 位元足以讓碰撞在實際中不成為問題。