正确写法是在UNIQUEIDENTIFIER列上设DEFAULT NEWID()约束,插入时省略该列;NEWSEQUENTIALID()生成顺序UUID,避免聚集索引碎片,但仅限默认约束使用,不可手动调用。

SQL Server插入时用NEWID()生成UUID的正确写法
直接在列默认约束里用NEWID(),而不是在INSERT语句里手动生成。否则每次INSERT都得显式写值,既啰嗦又容易漏——尤其表字段多、有外键或触发器时。
典型做法是给UNIQUEIDENTIFIER类型列加默认值:
ALTER TABLE users ADD CONSTRAINT DF_users_id DEFAULT NEWID() FOR id;
之后插入时完全不用提该列:
INSERT INTO users (name, email) VALUES ('Alice', 'a@example.com');
执行后id自动填充为新UUID。注意:不能对已有数据批量加默认约束再期望它“回填”,DEFAULT只影响后续新行。
为什么不用NEWSEQUENTIALID()?它和NEWID()关键区别在哪
NEWSEQUENTIALID()生成的UUID是按时间/顺序递增的,而NEWID()是完全随机的。这直接影响聚集索引性能。
如果把UUID设为聚集索引主键(比如PRIMARY KEY CLUSTERED),用NEWID()会导致频繁页拆分、索引碎片高、写入变慢;NEWSEQUENTIALID()能缓解这个问题。
但NEWSEQUENTIALID()有硬限制:只能用在默认约束中,不能出现在SELECT或函数调用里,且无法在SSMS设计器里直接设置(需T-SQL):
ALTER TABLE orders ADD CONSTRAINT DF_orders_guid DEFAULT NEWSEQUENTIALID() FOR guid;
如果你不需要顺序性,或者主键是代理键(如INT IDENTITY),而UUID只是业务标识字段,那就放心用NEWID()。
常见错误:在INSERT里手动调用NEWID()导致重复或逻辑混乱
有人习惯这样写:
INSERT INTO products (id, name) VALUES (NEWID(), 'Laptop');
表面看没问题,但隐患不少:
- 应用层如果也生成UUID(比如C#用
Guid.NewGuid()),两边可能冲突或不一致 - 批量插入时,每行都要单独算一次
NEWID(),不如默认约束干净 - 复制/同步场景下,源库和目标库可能因
NEWID()重复生成相同值(极小概率但存在) - 触发器或计算列若依赖该ID,手动插入可能绕过预期逻辑
更稳妥的做法是让数据库层统一控制生成时机,即只靠默认约束。
兼容性与迁移注意事项
NEWID()从SQL Server 2000起就支持,无版本顾虑;但要注意客户端驱动是否识别UNIQUEIDENTIFIER类型。比如旧版ADO.NET可能把UUID读成字节数组而非Guid,需显式指定SqlDbType.UniqueIdentifier。
迁移到Azure SQL或SQL Server 2022时,NEWID()行为不变,但若启用了SEQUENCE或想用GENERATE_APPLICATION_LOCK等新机制替代,需重新评估——UUID本身不提供业务含义,别把它当订单号或短链ID用。
真正容易被忽略的是:UUID长度固定16字节,但字符串表示(如'D3B5F7A1-2E4C-4D9F-8A1B-C2D3E4F5A6B7')占36字符,日志、备份、网络传输开销比整数ID大得多。别只盯着“全局唯一”,忘了存储和查询成本。










