MySQL中不推荐直接用UUID()作主键,因其36字符长度大、无序导致页分裂严重、二级索引膨胀且查询性能差;优化方案是改用BINARY(16)存储并重排字节序,或升级至MySQL 8.0.13+使用DEFAULT(UUID())配合有序替代方案如UUID_SHORT()。

MySQL INSERT时用UUID()函数直接生成主键值
直接在 INSERT 语句里调用 UUID() 函数,就能让每一行插入时获得唯一字符串主键。它不依赖表结构变更,也不需要触发器或应用层生成,适合快速落地的场景。
常见错误是把 UUID() 当成默认值写进 CREATE TABLE 的列定义里——MySQL 5.7 及更早版本不支持函数作为列的默认值(8.0.13+ 才支持 DEFAULT UUID(),且仅限于字符串类型)。
- 必须写在
INSERT的VALUES或SELECT子句中,例如:INSERT INTO users (id, name) VALUES (UUID(), 'Alice'); -
UUID()返回的是 36 字符的字符串(含 4 个短横线),如'f4e0a6e2-9b6d-11ef-9c3a-00155d012345',对应字段类型得是VARCHAR(36)或CHAR(36) - 如果已有主键是
INT AUTO_INCREMENT,不能直接替换;需先ALTER TABLE修改字段类型和约束
用UUID_SHORT()替代UUID()提升性能和索引效率
UUID() 生成的字符串是无序的,会导致二级索引页频繁分裂、B+树深度增加,写入性能明显下降。对高并发插入敏感的业务,应优先考虑 UUID_SHORT() —— 它返回一个 64 位无符号整数,可存进 BIGINT UNSIGNED,天然支持顺序递增(基于服务器启动时间 + 服务器ID + 自增计数器)。
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- 使用前确保
server_id已在 MySQL 配置中设置(非 0 值),否则UUID_SHORT()会报错或返回重复值 - 示例:
INSERT INTO logs (id, msg) VALUES (UUID_SHORT(), 'system start'); - 注意:重启 mysqld 后计数器归零,但因含时间戳和 server_id,全局仍唯一;不过同一秒内超 16M 次插入可能冲突(极少见)
建表时设UUID为主键并避免手动传值
如果希望每次 INSERT 都自动填充 UUID,又不想每次写 UUID(),可以在建表时用 DEFAULT(MySQL 8.0.13+)或配合触发器(兼容老版本)。
- MySQL 8.0.13+ 推荐方式:
id VARCHAR(36) PRIMARY KEY DEFAULT (UUID());注意括号不能省,且必须用DEFAULT (UUID())而非DEFAULT UUID() - 老版本可用
BEFORE INSERT触发器:SET NEW.id = UUID();,但需确保插入时不显式指定id字段(否则触发器不覆盖) - 字段设为
NOT NULL是必须的,否则DEFAULT不生效;同时建议加UNIQUE约束(虽然主键已隐含)
UUID主键导致JOIN和ORDER BY变慢怎么办
UUID 字符串主键会让关联查询和排序显著变慢,尤其当被 JOIN 的表数据量大时。根本原因是字符串比较比整数慢,且无法利用 CPU 的整数指令加速;更关键的是,无序 UUID 导致磁盘 I/O 随机性高。
- 若业务允许,改用
UUID_SHORT()或ULID(需应用层生成)等有序 ID 方案 - 强制走覆盖索引:对常用查询字段建联合索引,避免回表,例如
INDEX idx_status_created (status, created_at, id) - 慎用
ORDER BY id—— 它几乎总是全表扫描;改用时间字段排序,或加LIMIT控制结果集大小 - 备份/导出时注意:UUID 字段内容不可读、不可预测,调试定位问题比自增 ID 困难得多
实际用起来,最易忽略的是字符集和排序规则影响——VARCHAR(36) 列若用 utf8mb4_unicode_ci,比较开销比 ascii_bin 高不少;线上表一旦用上 UUID 主键,后续想切回自增或迁移到 Snowflake,代价远超初期预估。










