核心概念
- uniqueidentifier:16 位元組二進位值,全域唯一識別碼 (GUID)
- NEWID():產生唯一識別碼,基於網卡 MAC 位址 + CPU 時鐘
- 與 IDENTITY 差異:不自動產生,需顯式呼叫 NEWID();無序、較大 (16 bytes vs 4/8 bytes)
基本語法與範例
建立資料表與預設值
CREATE TABLE MyUniqueTable (
UniqueColumn UNIQUEIDENTIFIER DEFAULT NEWID(),
Characters VARCHAR(10)
);
GO
-- 插入時自動產生 GUID
INSERT INTO MyUniqueTable (Characters) VALUES ('abc');
-- 或顯式指定
INSERT INTO MyUniqueTable VALUES (NEWID(), 'def');
GO
變數使用 NEWID()
DECLARE @myid UNIQUEIDENTIFIER;
SET @myid = NEWID();
PRINT 'Value of @myid is: ' + CONVERT(VARCHAR(255), @myid);
-- 輸出範例:6F9619FF-8B86-D011-B42D-00C04FC964FF
完整資料表範例:客戶主檔
CREATE TABLE cust (
CustomerID UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),
Company VARCHAR(30) NOT NULL,
ContactName VARCHAR(60) NOT NULL,
Address VARCHAR(30) NOT NULL,
City VARCHAR(30) NOT NULL,
StateProvince VARCHAR(10) NULL,
PostalCode VARCHAR(10) NOT NULL,
CountryRegion VARCHAR(20) NOT NULL,
Telephone VARCHAR(15) NOT NULL,
Fax VARCHAR(15) NULL
);
GO
INSERT INTO cust (CustomerID, Company, ContactName, Address, City, StateProvince, PostalCode, CountryRegion, Telephone, Fax)
VALUES (NEWID(), 'Wartian Herkku', 'Pirkko Koskitalo', 'Torikatu 38', 'Oulu', NULL, '90110', 'Finland', '981-443655', '981-443655');
INSERT INTO cust (CustomerID, Company, ContactName, Address, City, StateProvince, PostalCode, CountryRegion, Telephone, Fax)
VALUES (NEWID(), 'Wellington Importadora', 'Paula Parente', 'Rua do Mercado, 12', 'Resende', 'SP', '08737-363', 'Brasil', '(14) 555-8122', '');
-- 更多插入範例...
GO
指定特定 GUID 值 (測試/遷移用)
DECLARE @myid UNIQUEIDENTIFIER;
SET @myid = 'A972C577-DFB0-064E-1189-0154C99310DA'; -- 注意:標準 GUID 32 字元 + 4 連字號 = 36 字元
GO
進階應用場景
1. 分散式系統主鍵
- 多伺服器/離線端獨立產生主鍵,合併時零衝突
- 合併複寫、Peer-to-Peer 複寫必要條件
2. URL/API 公開識別碼
- 避免連續數字被推測資料量/遍歷攻擊
- 如:
/api/orders/6F9619FF-8B86-D011-B42D-00C04FC964FF
3. 暫存表/暫存資料關聯
- 跨 Session/Procedure 傳遞識別碼,不依賴序列
效能與儲存考量
| 面向 | uniqueidentifier | INT IDENTITY | BIGINT IDENTITY |
| 儲存大小 | 16 bytes | 4 bytes | 8 bytes |
| 索引大小 | 大 | 小 | 中 |
| 插入效能 | 隨機 I/O、頁分裂多 | 順序寫入、最佳 | 順序寫入 |
| 碎片率 | 高,需定期重建 | 低 | 低 |
| 適用場景 | 分散式、合併、安全性 | 單機、高寫入 | 單機、極大資料量 |
緩解策略
- NEWSEQUENTIALID() (僅限 DEFAULT 約束):
- 產生有序 GUID,大幅減少頁分裂
- 但可預測性稍高,不適用安全敏感場景
- 叢集索引改用 INT/BIGINT 代理鍵,uniqueidentifier 做非叢集唯一索引
- 填充因子 (Fill Factor) 設 80-90% 減少分裂
NEWID() vs NEWSEQUENTIALID()
| 特性 | NEWID() | NEWSEQUENTIALID() |
| 呼叫方式 | 任意處可呼叫 | 僅限 DEFAULT 約束 |
| 順序性 | 完全隨機 | 遞增 (重啟後可能重置) |
| 頁分裂 | 嚴重 | 輕微 |
| 可預測性 | 不可預測 | 部分可預測 |
| 安全性 | 高 | 中 |
結語
uniqueidentifier + NEWID() 是分散式系統、合併複寫、公開 API 識別碼的標準解法。單機高寫入場景請優先考慮 INT/BIGINT IDENTITY 或 NEWSEQUENTIALID() + 非叢集索引架構。選型前務必評估:分散式需求、寫入量、索引維護成本、安全性要求。