English
 电子信箱
 加入收藏

  威盾防火墙 >> 新闻中心 >> 威盾新闻 >> 数据库设计之主键的思考

 

数据库设计之主键的思考

威盾防火墙 2014-12-07

 

 根据第二范式,主键是必须的。主键还是是唯一的,主键也被作为外键引用建立表和表之间的关系。从这几个方面讨论主键(数据库是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被其他的表作为外键引用,建议你还是保留吧,还不然不好弄。
 
这一小节我想说的是主键的本质就是一个约束,标示唯一性。

相关内容: 最新内容:
SQL或HQL预编译语句,能够防止SQL注入,但是不能处理%和_特殊字[2014-12-07]
ASP木马Webshell的安全防范解决办法[2014-12-07]
如何用应用交付技术优化Oracle数据库?[2014-12-07]
黑客技巧:Google hacking实现以及应用[2014-12-07]
“小不点”伪装成播放软件下载恶意程序[2014-12-07]
ASP.NET木马及Webshell安全解决方案[2014-12-07]