uuid()最省事但不宜作主键,因无序写入致页分裂、空间大、可读性差;uuid_short()需唯一server_id且须bigint unsigned;自定义序列需建表+存储过程原子操作实现。

直接用 UUID() 最省事,但别当主键用
如果你只需要“唯一”,不关心顺序、长度或索引性能,UUID() 是 MySQL 内置最简单的方案。它返回 36 字符的字符串(如 'a1b2c3d4-e5f6-7890-1234-567890abcdef'),理论全局唯一。
但要注意:InnoDB 主键无序写入会引发页分裂,插入吞吐下降明显;VARCHAR(36) 占空间大,JOIN 和索引效率低;外部系统调试时肉眼难读。
所以它适合做辅助标识(如日志 trace_id、临时 token),不适合做订单表主键或高频查询字段。
UUID_SHORT() 要配对 server_id,否则大概率重复
UUID_SHORT() 返回的是 BIGINT UNSIGNED 整数,结构隐含 server_id + 启动秒数 + 自增计数器,天生适合当主键。
但它唯一性的前提非常硬性:
- 每台 MySQL 实例的
server_id必须是 1–255 之间的**唯一整数**(SELECT @@server_id查) -
server_id = 0或重复会导致高位相同,同一秒内计数器撞车就重复 - 字段必须定义为
BIGINT UNSIGNED,存成INT或VARCHAR会截断或转负 - 必须加
PRIMARY KEY或UNIQUE约束——函数本身不校验,靠数据库兜底拦截冲突
示例建表:
CREATE TABLE orders (id BIGINT UNSIGNED PRIMARY KEY, order_no VARCHAR(32));插入:
INSERT INTO orders (id, order_no) VALUES (UUID_SHORT(), 'ORD-20260603');
用存储过程模拟 Sequence,得靠 UPDATE ... SELECT 原子操作
真正可控、可重置、支持业务规则(比如按天编号)的方案,得自己建表 + 存储过程。核心是用单条 UPDATE 更新计数器,再用 SELECT 读出新值,靠事务隔离保证并发安全。
典型结构:
- 一张控制表,如
mysql_sequence,含seq_name(序列名)、seq_no(当前值)、last_date(用于日期重置) - 存储过程里先
UPDATE mysql_sequence SET seq_no = seq_no + 1 WHERE seq_name = 'order_id' - 再
SELECT seq_no INTO @new_id FROM mysql_sequence WHERE seq_name = 'order_id' - 注意:不能用
LAST_INSERT_ID(),那只是针对自增列的
如果要做「日序号」,就在 UPDATE 里加判断:
UPDATE sequence_pool SET val = IF(last_date <h3>别忽略复制模式——<code>UUID_SHORT()</code> 在 SBR 下主从不一致</h3> <p>如果你的 MySQL 开启了语句级复制(<code>binlog_format = STATEMENT</code>),<code>UUID_SHORT()</code> 在从库执行时会重新计算,结果和主库不同,导致主从数据错位。这是静默故障,很难排查。</p> <p>解决方法只有两个:</p>
- 切到行级复制(
ROW模式),这是推荐做法 - 彻底不用
UUID_SHORT(),改用基于表的 Sequence 方案(它走的是普通 DML,天然兼容所有复制模式)
真正上线前,务必在从库查一次 SELECT UUID_SHORT(),和主库比对是否一致。











