UUID_TO_BIN能节省55%存储空间,因CHAR(36)占36字节,而UUID_TO_BIN()输出为16字节二进制;BINARY(16)是唯一正确类型,且必须用第二个参数1实现时间戳左移以提升索引局部性。

为什么UUID_TO_BIN能节省55%存储空间
直接用CHAR(36)存UUID,每个值占36字节(含4个连字符);而UUID_TO_BIN()输出是16字节二进制,压缩比接近55%。这不只是主键变小——所有二级索引的叶子节点都存主键值,所以索引体积同步下降,缓冲池能缓存更多有效数据行。
必须用BINARY(16),不能用VARCHAR或CHAR
BINARY(16)是唯一正确的存储类型。用VARCHAR(36)或CHAR(36)哪怕加了UUID_TO_BIN()转换,MySQL仍会隐式转回字符串比较,失去二进制效率;更糟的是,如果字段定义是字符类型,UUID_TO_BIN()结果会被截断或填充空格,导致查询错乱。
- 建表语句必须写成:
id BINARY(16) PRIMARY KEY - 插入必须显式调用:
INSERT INTO t VALUES (UUID_TO_BIN(UUID()), ...) - 不能依赖触发器或默认值自动转换,除非你确认所有客户端入口都走同一套逻辑
UUID_TO_BIN(uuid, 1)比UUID_TO_BIN(uuid, 0)关键得多
MySQL 8.0.31+ 支持第二个参数:1表示“时间戳左移”,把UUIDv1中原本在中间的时间段(毫秒级)提到最前面,让生成的BINARY(16)具备时间局部性。而0只是简单去掉连字符、不做重排,仍是随机分布,页分裂问题没缓解。
- 旧数据若用
UUID_TO_BIN(uuid, 0)存的,新数据切到1会导致B+树排序错乱,不可混用 - 应用层无需改ID生成逻辑,但所有INSERT必须统一用
UUID_TO_BIN(..., 1) - 查询时想看可读格式,用
BIN_TO_UUID(id, 1),不是0
别忘了配套的查询与迁移陷阱
用BINARY(16)后,WHERE条件必须保持二进制上下文,否则隐式转换会让索引失效。
- 错误写法:
WHERE id = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'(字符串比较,全表扫描) - 正确写法:
WHERE id = UUID_TO_BIN('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 1) - 已有
CHAR(36)表迁移?先加BINARY(16)列,用UPDATE SET new_id = UUID_TO_BIN(old_id, 1)批量转换,再删旧列、改主键——别用ALTER TABLE MODIFY直接转类型,会锁表且可能出错
真正难的不是函数怎么写,而是确保整个链路——从应用生成、SQL拼装、批量导入、历史迁移、到只读查询——全部对齐UUID_TO_BIN(..., 1)这个约定。漏一处,性能就打回原形。











