Skip to content

GUID 到底是什麼?淺析 GUID 的結構、版本與唯一性

2026-05-24

標籤:Windows · GUID · 科普 · QuickGUID


如果你在 Windows 上做過開發,你一定見過它——一串長得像亂碼的十六進位字元:

6B29FC40-CA47-1067-B31D-00DD010662DA

它可能出現在登錄檔裡、專案設定檔裡、日誌輸出裡,或者某個報錯訊息的中間。你知道它叫 GUID,也知道它「應該是唯一的」,但你可能從沒認真想過——這串東西到底是什麼?它為什麼長這樣?它憑什麼不會重複?

今天我們就來聊聊這件事。

UUID 和 GUID:同一件事的兩個名字

先說一個很多人不知道的事實:GUID 和 UUID 是同一個東西。

  • UUID(Universally Unique Identifier,通用唯一識別碼)是正式名稱,定義在 RFC 4122 中。
  • GUID(Globally Unique Identifier,全域唯一識別碼)是微軟給它取的別名。

就這麼簡單。UUID 是標準名,GUID 是微軟在 COM、Windows API、.NET 等技術堆疊中使用的名稱。你在 Windows 上看到的 GUID 和你在 Linux 上看到的 UUID,本質上是一回事。

為了統一,本文後面主要用 GUID 這個名字——畢竟我們聊的是 Windows 開發。

GUID 的結構:看著亂,其實有規律

一個標準 GUID 長這樣:

6B29FC40-CA47-1067-B31D-00DD010662DA

8-4-4-4-12,總共 32 個十六進位字元(128 個二進位位元),用連字號分成 5 段。看著隨機,但其實是有結構的:

6B29FC40-CA47-1067-B31D-00DD010662DA
              ↑    ↑
             版本  變體

關鍵在第三段的第一個字元和第四段的第一個字元:

  • 版本號(Version):第三段的第一個十六進位位表示這個 GUID 是用什麼演算法產生的。1 表示 v1,4 表示 v4,7 表示 v7。
  • 變體(Variant):第四段的第一個十六進位位表示它遵循的是哪個標準規範。89AB 開頭表示遵循 RFC 4122——你日常見到的絕大多數 GUID 都是這個變體。

所以下次看到一串 GUID,只要瞄一眼第三段的首位,就能知道它是 v1、v4 還是 v7 產生的。這比看外表有用得多。

GUID 到底有哪幾個版本?

UUID 規範定義了多個版本,但實際在用的主要是三個:

v1:基於時間和 MAC 位址

v1 GUID 由目前時間戳記(精確到 100 奈秒)和網路卡的 MAC 位址組合產生。

優點:天然有序,按產生時間排列。缺點:暴露了產生時間,而且 MAC 位址是硬體資訊——這在隱私和安全上是硬傷。攻擊者拿到 v1 GUID 就能反推出你的網卡位址和產生時間。

所以現在很少有人用 v1 了,但你在老舊系統中還是能見到它的身影。

v4:純隨機

v4 是目前最常見的版本。除了版本號和變體位是固定的,其餘 122 個二進位位元全部由隨機數填充

沒有時間戳記,沒有硬體資訊,純靠隨機性保證唯一。簡單粗暴,但效果極好。

你的專案中 new Guid()uuid.uuid4()crypto.randomUUID() 產生的幾乎都是 v4。

v7:時間排序的新貴

v7 是 2024 年才正式納入標準的新版本。它把前 48 位元用來存毫秒級時間戳記,剩下的位元用隨機數填充。

為什麼要搞 v7?因為 v4 雖然好,但它完全隨機,沒辦法按時間排序。這對資料庫來說是個問題:

  • 資料庫用 GUID 做主鍵時,如果用 v4,因為完全隨機,插入順序和索引順序不一致,會導致 B+ 樹頻繁分裂,寫入效能下降。
  • v7 因為前半部分是時間戳記,天然按時間遞增,插入順序和索引順序基本一致,寫入效能好得多。

所以如果你的專案用 GUID 做資料庫主鍵,v7 是比 v4 更好的選擇。

「GUID 不會重複」——但網上那個段子算錯了

每次說到 GUID 唯一,總有人問:萬一重複了怎麼辦?

網路上流傳著一個說法:「v4 GUID 的碰撞機率小到可以忽略不計,每秒產生 10 億個,持續 10 億年也不會重複。」聽起來很安心,對不對?

但這個說法在數學上其實是錯的。

錯在哪?生日悖論

它掉進了一個經典的直覺陷阱——生日悖論

你可能聽過這個問題:一個房間裡需要多少人,才能讓「其中兩個人同一天生日」的機率超過 50%?直覺告訴你,一年 365 天,怎麼也得 180 個人吧?

實際上,只需要 23 個人就夠了。

原因在於,我們不是在看「某個人和某個特定日子」會不會撞,而是看「所有人之間兩兩搭配」會不會撞。人數一多,兩兩組合的數量急劇膨脹。

GUID 也是一樣的道理。我們不能只看「某一個 GUID 會不會碰巧等於另一個」,而是要看「已經產生的所有 GUID 之間,任意兩個會不會撞車」。組合數會隨總量呈平方級成長,遠比直覺告訴你的快得多。

真實的碰撞時間線

如果嚴格按照每秒 10 億個的速度不停歇地產下去,用生日悖論公式重新算一遍:

  • 10 年:碰撞機率約 1%
  • 33 年:碰撞機率約 10%
  • 86 年:碰撞機率約 50%

至於 10 億年?那時候碰撞的次數已經數不清了。

那還能放心用嗎?

當然能。上面的前提是「每秒 10 億個,不停歇」——現實中沒有任何應用能做到這個量級。

如果你整個系統的生命週期裡總共產生了 100 兆個 GUID(這已經是極度誇張的天文數字),碰撞機率也只有十億分之一

放心用吧。

日常開發中的 GUID 煩惱

了解了原理之後,回到實際。開發者日常和 GUID 打交道,真正的痛點不在於「它會不會重複」,而在於:

產生不方便

Windows 內建的 guidgen.exe 一次只能產生一個。在終端機裡?PowerShell 倒是可以:[guid]::NewGuid()。但如果你需要一次產生 50 個做測試資料呢?寫指令碼吧。

格式五花八門

同一個 GUID,在不同語言和場景下長得很不一樣:

6B29FC40-CA47-1067-B31D-00DD010662DA          // 標準格式
6B29FC40CA471067B31D00DD010662DA              // 無連字號
{6B29FC40-CA47-1067-B31D-00DD010662DA}        // 花括號(C#/COM)
urn:uuid:6B29FC40-CA47-1067-B31D-00DD010662DA // URN
aKXwnELGRYeysdADQClibto=                      // Base64

你從日誌裡複製一個 GUID,需要轉成 C 程式碼裡的 DEFINE_GUID 巨集格式?手動改吧。

從文字中提取很麻煩

日誌檔案裡散落著幾十個 GUID,你想把它們都找出來?肉眼掃描還是寫正規表示式?

regex
[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}

能用,但每次都要查一次才能寫對。

用 QuickGUID 解決這些問題

這些痛點其實都可以在一個工具裡解決。QuickGUID 是一款 Windows 原生的 GUID 工具箱:

  • 批量產生 v4 或 v7,最多一次 1,000 個
  • 10+ 種格式即時轉換:標準、無連字號、花括號、Base64、C 位元組陣列、DEFINE_GUID 巨集……全部即時預覽
  • 智慧提取:貼上日誌或原始碼,自動識別所有 GUID 並批量轉換
  • 即時裝飾器:引號、後綴、大小寫,全域切換,複製出來直接能用

完全免費,100% 離線。

寫在最後

GUID 是軟體開發中最不起眼但最可靠的基礎建設之一。128 個二進位位元,不需要中央協調,不需要連網,就能在全球範圍內保證唯一性。這個設計從誕生到現在已經超過 30 年,依然是分散式系統中識別碼的最佳實踐之一。

希望這篇文章幫你搞懂了 GUID 背後的那些「為什麼」。