SQL Server 中的 Uniqueidentifier 如何始終是全域唯一值?
根據有關 UniqueIdentifier 的 microsoft 文件,該值始終是全域唯一的,因為它基於網路時鐘和 CPU 時鐘時間,另一方面,相同的文件說
uniqueidentifier 列可能包含多次出現的單個 uniqueidentifier 值,除非還為該列指定了 UNIQUE 或 PRIMARY KEY 約束。
我無法得出唯一標識符(GUID)如何在全球範圍內唯一的結論,因為網路地址(Mac 地址)在兩個不同的網路上可以相同,GUID 如何在全球範圍內通過哪些組合是唯一的,以及為什麼微軟這麼說應該是主要或唯一約束,以確保我們始終擁有唯一的 UniqueIdeifer 值。
https://technet.microsoft.com/en-us/library/ms190215(v=sql.105).aspx
問題 #1
根據有關UniqueIdentifier 的 Microsoft 文件,此值始終是全域唯一的,因為它基於網路時鐘和 CPU 時鐘時間… (已添加重點)
這裡的主要問題是您將兩個不同的事物混淆為兩個術語,它們指的是一件事:UNIQUEIDENTIFIER 和 GUID。
UNIQUEIDENTIFIER
是一種數據類型。數據類型定義了它們(即這種類型的列和變數)可以包含的數據的性質(例如,最小值/最大值等)和數據的某些行為(例如,如何處理比較)。此特定數據類型僅保存GUID / UUID 值。但它不是數據,所以唯一性的概念不適用於它。並且“UniqueIdentifier”名稱中的“Unique”一詞並不是關於實際唯一性的承諾,甚至不是聲明。- GUID / UUID 是可以儲存為的實際值
UNIQUEIDENTIFIER
,但也可以儲存為VARBINARY
/BINARY
,(N)VARCHAR
/(N)CHAR
,也許還有其他一些。雖然UNIQUEIDENTIFIER
數據類型是儲存這些值的最佳選擇(在 SQL Server 中),但將值儲存在其他類型中不會使這些值或多或少具有唯一性。問題 #2
我無法得出唯一標識符(GUID)如何在全球範圍內唯一的結論,因為網路地址(Mac 地址)在兩個不同的網路上可以相同
這裡的第二個問題是您實際上接受了您連結到的文件中的技術錯誤。我假設您指的是此聲明:
GUID 是唯一的二進制數;世界上沒有其他電腦會生成該 GUID 值的副本。
該語句指的是
NEWID()
在 T-SQL 和Guid.NewGuid()
.NET 中創建新 GUID / UUID 值的函式,以及它們始終生成唯一值的意圖。然而,這不是現實:新生成的 GUID 不能保證是唯一的。正如您已經指出的那樣,MAC 地址不一定是唯一的(它們甚至可以被欺騙;更多資訊請參見下面的“相關資訊”部分)。此外,來自其他 Microsoft 文件:
- .NET Guid Structure狀態的 MSDN 頁面(已添加重點):
GUID 是一個 128 位整數(16 個字節),可以在需要唯一標識符的所有電腦和網路中使用。這樣的標識符被複製的機率非常低。
- .NET Guid.NewGuid()方法(用於生成新的 GUID / UUID 值)呼叫Win32Native.CoCreateGuid。該功能的文件狀態(強調添加):
非常確定地,這個函式返回一個唯一的值——在相同或任何其他系統(網路或非網路)上的任何其他呼叫都不應該返回相同的值。
請注意,非 SQL Server 文件甚至沒有提到 MAC 地址。並且文件
CoCreateGuid
指向了生成的真正函式:UuidCreate。該函式的文件指出:出於安全原因,通常希望防止網路上的乙太網地址在公司或組織之外可用。UuidCreate函式生成的UUID無法追溯到生成它的電腦的乙太網地址**。它也不能與在同一台電腦上創建的其他UUID關聯。如果您不需要此級別的安全性,您的應用程序可以使用UuidCreateSequential函式,該函式的行為與所有其他作業系統版本上的UuidCreate**函式完全相同。
這裡的含義是不使用 MAC 地址(除非使用
NEWSEQUENTIALID()
)。事實上,在 SQL Server 中通過生成一些 GUIDNEWID()
表明它們是RFC 4122 版本 4 UUID,它們極有可能是唯一的。這裡有一個圖表,Random UUID probability of duplicates,它顯示了重複的可能性有多大。然而,即使是非常非常低的重複機率也不能保證唯一性。所以…
無法保證新生成的 GUID/UUID 值是唯一的。而且,即使有保證,
UNIQUEIDENTIFIER
數據類型仍然與實際唯一性無關(如 Brent 的回答所示)。唯一性,一個或多個列(即數據,而不是數據類型)只能由唯一索引/約束強制執行。相關資料:
因為 UNIQUEIDENTIFIER 列可以儲存您放入其中的任何 UNIQUEIDENTIFIER。拿這個程式碼:
CREATE TABLE dbo.Test (MyID UNIQUEIDENTIFIER); INSERT INTO dbo.Test VALUES ('809A6AA3-E6D7-4099-8D6C-6B21ED732013'); INSERT INTO dbo.Test VALUES ('809A6AA3-E6D7-4099-8D6C-6B21ED732013'); INSERT INTO dbo.Test VALUES ('809A6AA3-E6D7-4099-8D6C-6B21ED732013'); SELECT * FROM dbo.Test;
沒有什麼可以阻止您這樣做 - 除非您指定有關強制唯一性的表的某些內容。