智能视觉闭环管控渣土车:从识别算法到证据链的落地实践
2026/9/29 8:46:50
主键(Primary Key, PK)不仅是“唯一标识一行数据”的约束,更是 InnoDB 的物理组织方式:InnoDB 的表数据按主键构建聚簇索引(Clustered Index),数据行存放在主键 B+Tree 的叶子节点上。
这意味着:
本文从工程实践出发,比较自增主键、UUID 及常见分布式 ID,并给出可落地的选型建议与 DDL 示例。
把主键选型拆成 6 个维度,更容易做“最优方案”的工程权衡:
下面按“工程上最常见的几类主键”进行对比。
BIGINT UNSIGNED AUTO_INCREMENT)特点
优点
缺点
推荐场景
DDL 示例
CREATETABLEorders(idBIGINTUNSIGNEDNOTNULLAUTO_INCREMENT,user_idBIGINTUNSIGNEDNOTNULL,statusTINYINTNOTNULL,created_atDATETIMENOTNULL,PRIMARYKEY(id),KEYidx_user_created(user_id,created_at))ENGINE=InnoDB;CHAR(36)/VARCHAR(36))特点
550e8400-e29b-41d4-a716-446655440000。优点
缺点(工程上很关键)
推荐场景
BINARY(16))特点
CHAR(36)紧凑很多。MySQL 8.0 推荐用法(减少随机写)
MySQL 8.0 提供UUID_TO_BIN()/BIN_TO_UUID(),并支持“交换时间字段”的优化,使 UUID 更接近按时间递增,减少页分裂:
CREATETABLEevents(idBINARY(16)NOTNULL,created_atDATETIMENOTNULL,payload JSONNOTNULL,PRIMARYKEY(id))ENGINE=InnoDB;INSERTINTOevents(id,created_at,payload)VALUES(UUID_TO_BIN(UUID(),1),NOW(),JSON_OBJECT('k','v'));SELECTBIN_TO_UUID(id,1)ASid_textFROMeventsLIMIT10;其中第二个参数1会对 UUID 的部分字节做重排,让新生成的 UUID 在索引上更“顺序”。
优缺点总结
CHAR(36):空间与索引体积大幅改善。这类方案的目标是兼得:
常见实现:
优点
BIGINT(8 字节)时索引紧凑。缺点
推荐场景
DDL 示例(以BIGINT存储分布式 ID)
CREATETABLEtrade(idBIGINTUNSIGNEDNOTNULL,buyer_idBIGINTUNSIGNEDNOTNULL,amountDECIMAL(18,2)NOTNULL,created_atDATETIMENOTNULL,PRIMARYKEY(id),KEYidx_buyer_created(buyer_id,created_at))ENGINE=InnoDB;例如用(tenant_id, order_no)作为主键。
优点
缺点
推荐实践
UNIQUE约束。CREATETABLEtenant_order(idBIGINTUNSIGNEDNOTNULLAUTO_INCREMENT,tenant_idBIGINTUNSIGNEDNOTNULL,order_noVARCHAR(64)NOTNULL,created_atDATETIMENOTNULL,PRIMARYKEY(id),UNIQUEKEYuk_tenant_orderno(tenant_id,order_no))ENGINE=InnoDB;InnoDB 的二级索引叶子节点存储的是主键值而不是行指针,所以:
BIGINT变为CHAR(36),二级索引体积可能成倍增长。二级索引变胖会带来:更高的磁盘与内存消耗、更低的缓存命中、更高的写放大。
这就是为什么“UUID 文本主键”在写入压力上去后,往往比自增慢很多。
BIGINT UNSIGNED AUTO_INCREMENTpublic_id(UUID/ULID)并加唯一索引,作为对外标识。BIGINT(雪花/号段)作为主键。BINARY(16)的可排序 UUID/ULID(写入与索引体积通常优于CHAR(36))。BIGINT)。CHAR(36)UUID 主键。BINARY(16)UUID。UNIQUE,主键仍用短代理键。CREATETABLEuser_profile(idBIGINTUNSIGNEDNOTNULLAUTO_INCREMENT,public_idBINARY(16)NOTNULL,nicknameVARCHAR(64)NOTNULL,created_atDATETIMENOTNULL,PRIMARYKEY(id),UNIQUEKEYuk_public_id(public_id))ENGINE=InnoDB;写入时:
INSERTINTOuser_profile(public_id,nickname,created_at)VALUES(UUID_TO_BIN(UUID(),1),'alice',NOW());CREATETABLEmessage(idBIGINTUNSIGNEDNOTNULL,room_idBIGINTUNSIGNEDNOTNULL,sender_idBIGINTUNSIGNEDNOTNULL,contentTEXTNOTNULL,created_atDATETIMENOTNULL,PRIMARYKEY(id),KEYidx_room_created(room_id,created_at))ENGINE=InnoDB;INT省空间:大多数长期业务更建议从一开始就用BIGINT UNSIGNED,避免未来扩容与迁移。CHAR(36)主键通常是最差的组合(大 + 随机)。| 你的约束/目标 | 更优选择 |
|---|---|
| 单库单写、追求性能、实现简单 | BIGINT UNSIGNED AUTO_INCREMENT |
| 多写入节点、全局唯一、写入仍要稳 | 分布式趋势递增BIGINT(雪花/号段) |
| 必须应用侧生成、且希望索引别太大 | BINARY(16)+UUID_TO_BIN(UUID(), 1) |
| 要对外不可枚举,但内部仍要高性能 | 内部自增 PK + 对外public_id唯一索引 |
| 业务唯一键稳定且短 | PK 用代理键,业务键加UNIQUE(更常见) |
BIGINT UNSIGNED AUTO_INCREMENT(单写场景),简单、快、省。BIGINT(雪花/号段),兼顾唯一与写入性能。BINARY(16),并使用可排序/重排策略,避免CHAR(36)做主键。