mysql中uuid()函数返回36字符字符串,如'f4185127-3a24-11ef-9e5d-00155df3a0b5',符合rfc 4122 v1规范,需char(36)存储,无序性导致插入性能差,不支持insert returning获取,须应用层显式生成与使用。

MySQL里UUID()函数返回的是什么格式
它返回一个 36 字符的字符串,形如 'f4185127-3a24-11ef-9e5d-00155df3a0b5',含 4 个短横线,大小写混合(实际全小写),符合 RFC 4122 版本 1 规范(基于时间戳 + MAC 地址或随机数)。不是二进制,不是整数,不能直接当主键用而不考虑索引效率。
常见错误现象:INSERT 后发现主键字段被截断成 32 位、乱码或报错 Data too long for column——大概率是字段定义成了 VARCHAR(32) 或 CHAR(32),但实际需要至少 CHAR(36)。
-
UUID()每次调用都生成新值,不接受参数,不能指定版本(MySQL 8.0.31+ 才支持UUID_TO_BIN()和UUID_FROM_BIN()) - 如果要存为二进制节省空间,得配合
UUID_TO_BIN(<code>UUID(), 1)(注意第二个参数1表示交换时间戳字节序,否则范围扫描失效) - 直接存字符串最简单,但
CHAR(36)比BINARY(16)多占一倍空间,且索引比较慢(字符串比对 vs 字节比对)
用UUID()做主键时为什么插入变慢了
因为 UUID 是无序的,每次新值都可能插入到 B+ 树索引中间位置,导致频繁页分裂和磁盘随机写。尤其在高并发批量插入时,性能会明显低于自增 INT 或 BIGINT 主键。
使用场景:适合分布式系统、分库分表、客户端预生成 ID、避免暴露业务增长信息等;不适合高频写入、单机 OLTP 核心订单表。
- 别在大表上直接把
id改成CHAR(36) PRIMARY KEY DEFAULT (UUID())—— MySQL 8.0.13+ 才支持函数默认值,且只对INSERT有效,UPDATE不触发 - 如果真要用,建议搭配
UUID_TO_BIN(<code>UUID(), 1) 存为BINARY(16),并建前缀索引或用ORDER BY优化范围查询 - 注意从应用层生成 UUID(比如 Python 的
uuid.uuid4().hex)再传入,比让 MySQL 每行都调用UUID()更可控、更易测试
UUID_SHORT()能替代UUID()吗
不能混用。UUID_SHORT() 返回的是一个 64 位无符号整数(BIGINT UNSIGNED),格式类似 1152921504606846976,由服务器启动时间、服务器 ID、单调计数器拼成,**不是标准 UUID**,也不带短横线,无法被外部系统识别为 UUID。
常见错误现象:用 UUID_SHORT() 当主键后,导出数据到其他系统(比如 Elasticsearch、Go 服务)报类型不匹配,或前端解析失败——因为对方 expecting a string like 'xxxx-xxxx-xxxx-xxxx'。
-
UUID_SHORT()要求server_id非零且唯一,多节点部署时必须手动配置,否则不同实例可能生成重复值 - 它的值是递增的,索引友好,性能接近自增主键,但牺牲了全局唯一性和可移植性
- 如果只是想避开自增暴露业务量,又不需要跨系统兼容 UUID,
UUID_SHORT()是个轻量替代,但别把它当成UUID()的“更快版本”
生成后怎么安全地插入并获取 ID
MySQL 不支持像 PostgreSQL 那样在 INSERT ... RETURNING 里直接取函数结果。如果靠 LAST_INSERT_ID(),它对 UUID() 完全无效(只对自增列生效)。
所以必须显式生成、显式插入、显式返回——要么在应用层做,要么用存储过程封装。
- 推荐方式:应用层调用一次
SELECT UUID(),拿到值后拼进INSERT INTO t(id, name) VALUES (?, ?),再把这个值当业务 ID 用 - 如果非要在 SQL 层搞定,可用变量:
SET @new_id = UUID(); INSERT INTO t(id, name) VALUES (@new_id, 'test'); SELECT @new_id;,但注意变量作用域仅限当前 session - 别用触发器自动设
UUID()——不可见、难调试、事务中多次调用行为不一致(比如批量插入时每行都重算)











