根据第二范式,主键是必须的。主键还是是唯一的,主键也被作为外键引用建立表和表之间的关系。从这几个方面讨论主键(数据库是Oracle):
1.主键的命名
最近看到由于架构使用hibernate的原因,导致所有主键的命名是ID,我觉得非常糟糕,如部门表(department),用户表(user),角色表(role),这些表如果关联都是id之间关联,非常难辨认这个叫ID是那张表的,如果改为department_id,user_id,role_id是不是很舒服,一看就知道是那张表的ID。可惜架构限制,即使开发人员不断抱怨,也没办法。
2.选什么字段做为主键
选择主键是找一个自然键(与业务有关系的键),还是建一个与业务模型毫无关系的键呢?打个比方:
部门表(department)有个部门code是唯一的,编码规则如,
百度公司 01
百度公司/研发部 0101
百度公司/研发部/搜索引擎开发组 010101
设备表(device)有设备code这个字段,这个字段是根据设备的一些属性生成的一个唯一标识。
我的建议是建一个毫无业务意义的字段,原因是什么呢?
部门是会调整的,一个部门从这个大部门下调整到其他的大部门下是常有的事情,有很多业务关联的部门的信息,如果基表进行调整,那需要把业务的数据都刷新了。
设备表的code也可能会变,因为设备类型每年都有调整,只要一调整code就变化了,同部门一样。
说到这有兄弟不服气了,我们公司的设备表code不调整。我想说的是你不可能预测未来,只要是业务,都可能会发生变化。
3.主键是选择序列还是uuid
如果你的系统是小系统,数据量不大,那就没有什么讲究。
a.如广东有21个地市局,在每个局都发布一个系统,每天都要把地市局的数据抽取到省公司整合。要是用序列,要把序列前面加上这个局的标记,如果不做任何加工,把数据抽取到省公司整合会很难过的。如果用uuid则不需要考虑这个问题,人家号称全球唯一。
b.用序列,uuid哪个性能好?这个我还真测试过,uuid没有序列性能好,只是差一点点,可以忽略。uuid是32位的varchar2,占用空间比序列大多了,所以性能差点不足为奇。哪不是说任何场景序列就比uuid好呢?不能这么说,序列有一个问题,是我长期的性能调优发现的,用序列可能造成SQL语句时快时慢的问题。如果正常使用序列,主键是连续的,不会出现问题,难的是有时候不可能,如你的部门id从1到100,由于数据迁移的原因,你想区分以前的部门id和迁移后的,你把序列从10000开始,这样会造成数据不均匀。如果你知道直方图,绑定窥探,那我就不用解释了。
4.还有一个特殊的情况,现在有部门表(department),用户表(user),还有一张关联表,这种关联表可能会出现重复的问题。
create table dept_user_relation
(
relation_id NUMBER(18)primary
key,
department_id NUMBER(18),
user_id NUMBER(18)
);
RELATION_IDDEPARTMENT_ID USER_ID
----------- ------------- ----------
1 100 100
2 100 100
3 100 100
你会发现主键relation_id没起作用啊!是的,需要在department_id和user_id上加唯一约束,当你加了约束,你又会发现要这个relation_id有什么用呢?是的,它可能没有用。
a.如果relation_id没有被其他的表作为外键引用,你可以用department_id和user_id联合起来作为主键。但我觉得留着也没啥问题,当然,如果你是处女座,那只有删除relation_id。
b.如果relation_id被其他的表作为外键引用,建议你还是保留吧,还不然不好弄。
这一小节我想说的是主键的本质就是一个约束,标示唯一性。