SQL插入数据时动态生成全局唯一标识符
不同数据库的UUID生成函数互不相同:MySQL使用UUID()并配合CHAR(36)类型,SQLServer采用NEWID()或NEWSEQUENTIALID(),PostgreSQL建议选用pgcrypto扩展中的gen_random_uuid()。在跨数据库应用环境下,应当设计一个方言适配层,或者在应用层统一生成UUID值,避免在SQL语句中硬编码具体
数据库原生UUID生成,确实是最稳妥的方案,前提是选对数据库对应的函数。MySQL用UUID()配合CHAR(36),SQL Server用NEWID()或NEWSEQUENTIALID()配合UNIQUEIDENTIFIER,PostgreSQL优先用pgcrypto扩展的gen_random_uuid()配合UUID类型。跨库场景下,要么抽象出方言适配层,要么在应用层统一生成——别指望一条SQL打通所有数据库。

直接调用数据库原生函数是性价比最高的做法,没必要自己拼字符串或依赖应用层生成——除非你明确需要跨库一致性,或者对ID格式有特殊要求。
MySQL 8.0+ 用 UUID(),但字段类型和长度得配对
UUID() 返回的是36字符的带连字符字符串(如 550e8400-e29b-41d4-a716-446655440000),不是二进制格式。如果建表时用了 CHAR(36) 或 VARCHAR(36),能正常存储;但要是用了 CHAR(32),连字符会被截断,数据就坏了。
- 建表推荐写法:
id CHAR(36) DEFAULT UUID() PRIMARY KEY - 插入时不用显式指定该字段,触发默认值即可:
INSERT INTO users (name) VALUES ('Alice') - 千万别在 WHERE 条件里用
UUID()做等值匹配——它每次调用都会生成新值,WHERE id = UUID()永远不成立 - 性能方面,UUID 本身无序,作为聚簇主键会导致频繁页分裂。高并发写入场景下,建议搭配
INNODB的ROW_FORMAT=COMPRESSED,或者干脆改用自增ID,再单独加一个唯一索引
SQL Server 必须用 NEWID() 或 NEWSEQUENTIALID(),不能混用
NEWID() 生成随机GUID,NEWSEQUENTIALID() 生成递增GUID,两者行为差异很大。而且 NEWSEQUENTIALID() 只能用在列默认值定义中,不能在 INSERT 或 SELECT 表达式里直接调用。
- 建表时设默认值:
id UNIQUEIDENTIFIER DEFAULT NEWID() PRIMARY KEY - 想减少索引碎片?换成
DEFAULT NEWSEQUENTIALID(),但注意它不能在INSERT ... VALUES (NEWSEQUENTIALID(), ...)中直接调用,否则会报错Invalid use of 'NEWSEQUENTIALID' - 别把
UNIQUEIDENTIFIER字段设成NOT NULL却不设默认值,也不显式插入——那样插入会失败 - 如果要用短ID(比如
UID12345678),得靠计算字段或触发器实现。但NEWID()本身不支持截取后设默认值,因为函数有副作用,不能在列定义里直接用
PostgreSQL 要先装扩展,gen_random_uuid() 才可用
PostgreSQL 默认不提供 UUID 生成函数。uuid-ossp 需要超级用户权限才能启用,CI 环境里经常卡住;pgcrypto 更轻量,普通用户也能安装,推荐优先用这个。
- 启用扩展:
CREATE EXTENSION IF NOT EXISTS "pgcrypto" - 建表:
id UUID DEFAULT gen_random_uuid() PRIMARY KEY - 插入:
INSERT INTO users (name) VALUES ('Bob'),字段自动填充 - 别误写成
uuid_generate_v4()—— 它属于uuid-ossp,没装扩展会报错function uuid_generate_v4() does not exist gen_random_uuid()生成的是 RFC 4122 v4 UUID,无序;如果需要时间有序的UUID,得用第三方扩展如pg_uuidv7,不在原生范围内
真正容易被忽略的点是:跨数据库迁移脚本时,UUID()、NEWID()、gen_random_uuid() 三者语法不兼容,硬编码函数名等于埋雷。如果项目要支持多库,要么统一用应用层生成(比如 Python 的 uuid.uuid4().hex),要么抽象出方言适配层,别指望一条 SQL 走天下。
