primary key从integer改float方法及层级成员表设计方案咨询
方案合理性结论
你提出的将integer主键修改为float类型存储层级ID的方案完全不可行,核心问题如下:
- float属于非精确浮点数类型,存储值存在固有精度偏差,比如你预期存入的
1.001可能实际存储为近似值,主键要求全局唯一、精确匹配,精度问题会直接导致关联查询、外键校验、数据定位全部出错 - 扩展性极差:你当前设计的三位小数位最多给每个主体挂载999个子成员,一旦企业下属员工数超过阈值,或者后续需要新增三级、四级成员层级,现有ID规则直接失效,全量修改主键的业务成本、故障风险极高
- 违背主键设计原则:主键的唯一作用是唯一标识表内一行记录,不应该承载任何业务属性(包括层级关系),将层级规则耦合进主键,后续任何业务规则调整都要改动核心主键,会给后续迭代埋大量隐患
- 排序可靠性差:浮点数的排序结果在不同数据库引擎、不同数据量级下可能出现和预期不符的问题,无法稳定支撑你需要的层级排序需求
推荐的最优实现方案
完全不需要改动原有主键,用邻接表模型就能低成本实现子成员管理需求,改动量极小、兼容性拉满:
- 保留原有
id字段:继续用integer类型作为主键,所有现有业务逻辑、表关联关系完全不需要改动 - 新增
parent_id字段:integer类型,默认值设为NULL,字段值指向当前成员所属上级主体的id:企业类成员的parent_id为NULL,企业下属的子成员parent_id填写对应企业的id - 给
parent_id字段加普通索引,查询某企业下所有子成员直接执行WHERE parent_id = [对应企业ID]即可,查询性能远高于解析float格式主键 - 如果需要实现稳定的层级排序,额外新增一个varchar类型的
hierarchy_path字段即可,比如ID为1的企业路径存0001,其下ID为25的子成员路径存0001/0025,需要排序时直接按该字段做字典序排序,支持无限层级扩展,不存在ID数量上限问题 - 如果你需要给前端展示
1.001这类带层级的编号,直接在业务查询层做拼接计算即可,不要把展示层的格式要求和数据库物理主键设计混为一谈
关于修改主键类型的说明
非常不建议通过修改主键类型的方式实现该需求,如果你因为特殊原因必须修改主键(再次强调不推荐),通用操作步骤如下,操作前必须做全量数据备份:
- 先删除所有关联
members.id的外键约束 - 将
members.id字段类型修改为目标类型(如果一定要存精确小数请用DECIMAL,绝对不要用FLOAT) - 重新为
id字段添加主键约束 - 同步修改所有关联表中存储
members.id的外键字段类型,重建之前删除的外键关系
注意:该操作在数据量较大时会锁表导致业务长时间中断,且存在数据截断、关联失效的风险,非极端情况不要执行。
内容的提问来源于stack exchange,提问作者lina_2299
相关产品推荐
相关产品推荐

