一聚教程网:一个值得你收藏的教程网站

热门教程

如何使用SQL的NEWID函数产生全局唯一标识符?

时间:2026-07-12 09:35:51 编辑:袖梨 来源:一聚教程网

NEWID() 在 SQL Server 中每次调用均生成无序随机 GUID,保证全局唯一但引发聚集索引页分裂;不可作时间有序 ID 使用,需有序 GUID 时应改用 NEWSEQUENTIALID()(仅限默认约束),INSERT 的 VALUES 子句中可直接调用 NEWID()。

NEWID() 在 SQL Server 中生成 GUID 的实际效果

NEWID() 是 SQL Server 专用函数,每次调用都返回一个全新的 uniqueidentifier 值,本质是随机生成的 128 位 GUID。它不依赖时间戳或机器信息,因此在分布式场景下也能保证全局唯一性——但代价是完全无序,插入时容易导致聚集索引页分裂。

常见误用是把它当“时间有序 ID”用,结果发现主键索引性能断崖式下降。如果你需要有序 GUID,得换用 NEWSEQUENTIALID()(仅限默认约束),不能直接在 INSERT 中调用。

INSERT 语句中直接使用 NEWID() 的写法与限制

可以在 INSERT 的 VALUES 子句里直接调用 NEWID()),适用于单条或批量插入时需为每行生成独立 ID 的场景:

INSERT INTO users (id, name) VALUES (NEWID(), 'Alice'), (NEWID(), 'Bob');

注意以下几点:

  • NEWID() 每次出现在表达式中都会重新计算,所以 SELECT NEWID(), NEWID() 返回两个不同值
  • 不能在视图定义、聚合函数或 WHERE 条件中“稳定引用”该值;想复用同一个 GUID,必须先存入变量:DECLARE @id UNIQUEIDENTIFIER = NEWID(); INSERT ... VALUES (@id, ...);
  • 在触发器或计算列中慎用——可能引发不可预期的多次求值

用 NEWID() 实现随机抽样时的性能陷阱

很多人用 ORDER BY NEWID() 实现随机排序,比如取 10 条随机记录:

SELECT TOP 10 * FROM products ORDER BY NEWID();

这看似简洁,但实际会为表中每一行都调用一次 NEWID()),再全量排序,数据量稍大(如 >10 万行)就明显变慢。更高效的做法是:

  • 小表(
  • 中大表:改用 TABLESAMPLE(如 SELECT * FROM products TABLESAMPLE (10 PERCENT)),但不保证精确行数
  • 严格要求 N 行且性能敏感:用窗口函数 + CHECKSUM(NEWID()) 降序取 Top N,避免全排序

跨数据库兼容性问题——别在非 SQL Server 环境硬套 NEWID()

PostgreSQL 用 gen_random_uuid()(需 pgcrypto 扩展),MySQL 用 UUID()(格式为 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,但不是真正的随机 GUID,含时间成分),SQLite 则没有内置 UUID 函数,得靠应用层生成。

如果项目要兼容多数据库,不要在 SQL 层硬写 NEWID()),要么统一由应用生成 UUID4 后传入,要么抽象出数据库适配层。直接迁移 SQL 脚本时,这个函数是最常被卡住的点之一。

热门栏目