前言
你是否创建过下面结构的表
userid | 用户id(主键列) |
username | 张三 |
用唯一的用户id作为主键。而为了业务需要,你的userid可能是由一个组件根据某种规则生成的,生成后再存入数据库。看起来并没有什么问题,当一个需求要维护所有的用户信息时百分之90的人都会这样建表。
假如在原来表结构的基础上,需求变更为:每个用户在不同的场景下被视为不同的用户,既用户现在又多了一个场景的概念,在场景1中他可能是张三,但是在场景2中他就是李四了。在此需求下,用户id+场景id才是唯一的,单纯的用户id已经不唯一了。在如此场景下我们可能需要再去建立一张表,用来标志用户和场景一对多的关联关系。变成:
userid | 用户id(主键列) |
username | 用户名 |
id | 无业务含义 |
userid | 用户id |
type | 场景类型 |
由上可以看出,最开始设计的userid主键会因为业务的改变而让整个系统复杂度提高。虽然这是业务变动的常态,但是作为程序员,我们需要让自己的系统更加灵活,更好的适应繁杂的业务。那么如何去设计一个合理的主键呢?
使用与业务无关的自增主键
基于上面的情况,我们在一开始设计表的时候就可以使用这种结构:
id | 无业务含义(自增主键列) |
userid | 用户id |
username | 用户姓名 |
以一个与业务无关的自增列作为主键。这样的灵活性要比直接使用用户id作为主键更高,可以随时根据业务进行变更,即使表中数据的对应关系从一对一变成一对多,多对多,都可以应对。并且自增主键可以加快数据插入的效率。
说说坏处
1.由于自增列并没有实际业务含义,所以我们的查询还是要走其他的列,这就无法避免的还需要在其他列上建立索引。与之前相比,需要再多建一个索引,这就造成了磁盘空间的浪费。
2.自增主键在高并发下会有性能的瓶颈。
3.容易暴露业务体量
总结
“使用与业务无关的自增主键”,这句话我已经忘记了是从哪里看的了,当时嗤之以鼻觉得一个冗余的主键并没有太大的意义,并且在技术层面也是牺牲了查询效率和磁盘空间换取了插入效率,当时觉得并不划算。但是随着项目经验的增加,我的考虑角度慢慢从技术层面转到了业务层面,逐渐发现采用这种方式可以让业务有更大的灵活性。但应用过程中还是需要根据实际情况判断是否需要,在此只是提供一种表设计的思路。